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
22function italic($str) {
23	if (is_array($str)) {
24		foreach ($str as $key => $val) {
25			if (is_string($val)) {
26				$em = new CTag('em', true);
27				$em->addItem($val);
28				$str[$key] = $em;
29			}
30		}
31	}
32	elseif (is_string($str)) {
33		$em = new CTag('em', true, '');
34		$em->addItem($str);
35		$str = $em;
36	}
37	return $str;
38}
39
40function bold($str) {
41	if (is_array($str)) {
42		foreach ($str as $key => $val) {
43			if (is_string($val)) {
44				$str[$key] = new CTag('b', true, $val);
45			}
46		}
47
48		return $str;
49	}
50
51	return new CTag('b', true, $str);
52}
53
54function make_decoration($haystack, $needle, $class = null) {
55	$result = $haystack;
56
57	$tmpHaystack = mb_strtolower($haystack);
58	$tmpNeedle = mb_strtolower($needle);
59	$pos = mb_strpos($tmpHaystack, $tmpNeedle);
60
61	if ($pos !== false) {
62		$start = CHtml::encode(mb_substr($haystack, 0, $pos));
63		$end = CHtml::encode(mb_substr($haystack, $pos + mb_strlen($needle)));
64		$found = CHtml::encode(mb_substr($haystack, $pos, mb_strlen($needle)));
65
66		if (is_null($class)) {
67			$result = [$start, bold($found), $end];
68		}
69		else {
70			$result = [$start, (new CSpan($found))->addClass($class), $end];
71		}
72	}
73
74	return $result;
75}
76
77function nbsp($str) {
78	return str_replace(' ', SPACE, $str);
79}
80
81function prepareUrlParam($value, $name = null) {
82	if (is_array($value)) {
83		$result = '';
84
85		foreach ($value as $key => $param) {
86			$result .= prepareUrlParam($param, isset($name) ? $name.'['.$key.']' : $key);
87		}
88	}
89	else {
90		$result = '&'.$name.'='.urlencode($value);
91	}
92
93	return $result;
94}
95
96/**
97 * Get ready for url params.
98 *
99 * @param mixed  $param				param name or array with data depend from $getFromRequest
100 * @param bool   $getFromRequest	detect data source - input array or $_REQUEST variable
101 * @param string $name				if $_REQUEST variable is used this variable not used
102 *
103 * @return string
104 */
105function url_param($param, $getFromRequest = true, $name = null) {
106	if (is_array($param)) {
107		if ($getFromRequest) {
108			fatal_error(_('URL parameter cannot be array.'));
109		}
110	}
111	else {
112		if (is_null($name)) {
113			if (!$getFromRequest) {
114				fatal_error(_('URL parameter name is empty.'));
115			}
116
117			$name = $param;
118		}
119	}
120
121	if ($getFromRequest) {
122		$value =& $_REQUEST[$param];
123	}
124	else {
125		$value =& $param;
126	}
127
128	return isset($value) ? prepareUrlParam($value, $name) : '';
129}
130
131function url_params(array $params) {
132	$result = '';
133
134	foreach ($params as $param) {
135		$result .= url_param($param);
136	}
137
138	return $result;
139}
140
141function BR() {
142	return new CTag('br');
143}
144
145function get_icon($type, $params = []) {
146	switch ($type) {
147		case 'favourite':
148			if (CFavorite::exists($params['fav'], $params['elid'], $params['elname'])) {
149				$icon = (new CRedirectButton(SPACE, null))
150					->addClass(ZBX_STYLE_BTN_REMOVE_FAV)
151					->setTitle(_('Remove from favourites'))
152					->onClick('rm4favorites("'.$params['elname'].'", "'.$params['elid'].'");');
153			}
154			else {
155				$icon = (new CRedirectButton(SPACE, null))
156					->addClass(ZBX_STYLE_BTN_ADD_FAV)
157					->setTitle(_('Add to favourites'))
158					->onClick('add2favorites("'.$params['elname'].'", "'.$params['elid'].'");');
159			}
160			$icon->setId('addrm_fav');
161
162			return $icon;
163
164		case 'fullscreen':
165			$url = new CUrl();
166
167			if ($params['fullscreen'] == 0) {
168				$url->setArgument('fullscreen', '1');
169
170				$icon = (new CRedirectButton(SPACE, $url->getUrl()))
171					->setTitle(_('Fullscreen'))
172					->addClass(ZBX_STYLE_BTN_MAX);
173			}
174			else {
175				$url->setArgument('fullscreen', '0');
176
177				$icon = (new CRedirectButton(SPACE, $url->getUrl()))
178					->setTitle(_('Normal view'))
179					->addClass(ZBX_STYLE_BTN_MIN);
180			}
181
182			return $icon;
183
184		case 'dashconf':
185			$icon = (new CRedirectButton(SPACE, 'dashconf.php'))
186				->addClass(ZBX_STYLE_BTN_CONF)
187				->setTitle(_('Configure'));
188
189			if ($params['enabled']) {
190				$icon = [$icon, (new CDiv())->addClass(ZBX_STYLE_ACTIVE_INDIC)];
191			}
192
193			return $icon;
194
195		case 'screenconf':
196			return (new CRedirectButton(SPACE, null))
197				->addClass(ZBX_STYLE_BTN_CONF)
198				->setTitle(_('Refresh time'));
199
200		case 'overviewhelp':
201			return (new CRedirectButton(SPACE, null))
202				->addClass(ZBX_STYLE_BTN_INFO);
203
204		case 'reset':
205			return (new CRedirectButton(SPACE, null))
206				->addClass(ZBX_STYLE_BTN_RESET)
207				->setTitle(_('Reset'))
208				->onClick('timeControl.objectReset();');
209	}
210
211	return null;
212}
213
214/**
215 * Create CDiv with host/template information and references to it's elements
216 *
217 * @param string $currentElement
218 * @param int $hostid
219 * @param int $lld_ruleid
220 *
221 * @return object
222 */
223function get_header_host_table($current_element, $hostid, $lld_ruleid = 0) {
224	$options = [
225		'output' => [
226			'hostid', 'status', 'proxy_hostid', 'name', 'maintenance_status', 'flags', 'available', 'snmp_available',
227			'jmx_available', 'ipmi_available', 'error', 'snmp_error', 'jmx_error', 'ipmi_error'
228		],
229		'selectHostDiscovery' => ['ts_delete'],
230		'hostids' => [$hostid],
231		'editable' => true
232	];
233	if ($lld_ruleid == 0) {
234		$options['selectApplications'] = API_OUTPUT_COUNT;
235		$options['selectItems'] = API_OUTPUT_COUNT;
236		$options['selectTriggers'] = API_OUTPUT_COUNT;
237		$options['selectGraphs'] = API_OUTPUT_COUNT;
238		$options['selectDiscoveries'] = API_OUTPUT_COUNT;
239		$options['selectHttpTests'] = API_OUTPUT_COUNT;
240	}
241
242	// get hosts
243	$db_host = API::Host()->get($options);
244
245	if (!$db_host) {
246		$options = [
247			'output' => ['templateid', 'name', 'flags'],
248			'templateids' => [$hostid],
249			'editable' => true
250		];
251		if ($lld_ruleid == 0) {
252			$options['selectApplications'] = API_OUTPUT_COUNT;
253			$options['selectItems'] = API_OUTPUT_COUNT;
254			$options['selectTriggers'] = API_OUTPUT_COUNT;
255			$options['selectGraphs'] = API_OUTPUT_COUNT;
256			$options['selectScreens'] = API_OUTPUT_COUNT;
257			$options['selectDiscoveries'] = API_OUTPUT_COUNT;
258			$options['selectHttpTests'] = API_OUTPUT_COUNT;
259		}
260
261		// get templates
262		$db_host = API::Template()->get($options);
263
264		$is_template = true;
265	}
266	else {
267		$is_template = false;
268	}
269
270	if (!$db_host) {
271		return null;
272	}
273
274	$db_host = reset($db_host);
275
276	// get lld-rules
277	if ($lld_ruleid != 0) {
278		$db_discovery_rule = API::DiscoveryRule()->get([
279			'output' => ['name'],
280			'selectItems' => API_OUTPUT_COUNT,
281			'selectTriggers' => API_OUTPUT_COUNT,
282			'selectGraphs' => API_OUTPUT_COUNT,
283			'selectHostPrototypes' => API_OUTPUT_COUNT,
284			'itemids' => [$lld_ruleid],
285			'editable' => true
286		]);
287		$db_discovery_rule = reset($db_discovery_rule);
288	}
289
290	/*
291	 * list and host (template) name
292	 */
293	$list = (new CList())->addClass(ZBX_STYLE_OBJECT_GROUP);
294
295	if ($is_template) {
296		$template = new CSpan(
297			new CLink($db_host['name'], 'templates.php?form=update&templateid='.$db_host['templateid'])
298		);
299
300		if ($current_element === '') {
301			$template->addClass(ZBX_STYLE_SELECTED);
302		}
303
304		$list->addItem([
305			new CSpan(
306				new CLink(_('All templates'), 'templates.php?templateid='.$db_host['templateid'].url_param('groupid'))
307			),
308			'/',
309			$template
310		]);
311
312		$db_host['hostid'] = $db_host['templateid'];
313	}
314	else {
315		$proxy_name = '';
316
317		if ($db_host['proxy_hostid'] != 0) {
318			$db_proxies = API::Proxy()->get([
319				'output' => ['host'],
320				'proxyids' => [$db_host['proxy_hostid']]
321			]);
322
323			$proxy_name = CHtml::encode($db_proxies[0]['host']).NAME_DELIMITER;
324		}
325
326		$name = $proxy_name.CHtml::encode($db_host['name']);
327
328		switch ($db_host['status']) {
329			case HOST_STATUS_MONITORED:
330				if ($db_host['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) {
331					$status = (new CSpan(_('In maintenance')))->addClass(ZBX_STYLE_ORANGE);
332				}
333				else {
334					$status = (new CSpan(_('Enabled')))->addClass(ZBX_STYLE_GREEN);
335				}
336				break;
337			case HOST_STATUS_NOT_MONITORED:
338				$status = (new CSpan(_('Disabled')))->addClass(ZBX_STYLE_RED);
339				break;
340			default:
341				$status = _('Unknown');
342				break;
343		}
344
345		$host = new CSpan(new CLink($name, 'hosts.php?form=update&hostid='.$db_host['hostid']));
346
347		if ($current_element === '') {
348			$host->addClass(ZBX_STYLE_SELECTED);
349		}
350
351		$list->addItem([
352			new CSpan(new CLink(_('All hosts'), 'hosts.php?hostid='.$db_host['hostid'].url_param('groupid'))),
353			'/',
354			$host
355		]);
356		$list->addItem($status);
357		$list->addItem(getHostAvailabilityTable($db_host));
358
359		if ($db_host['flags'] == ZBX_FLAG_DISCOVERY_CREATED && $db_host['hostDiscovery']['ts_delete'] != 0) {
360			$lifetime_indicator = getHostLifetimeIndicator(time(), $db_host['hostDiscovery']['ts_delete']);
361			$list->addItem((new CDiv($lifetime_indicator))->addClass(ZBX_STYLE_STATUS_CONTAINER));
362		}
363	}
364
365	/*
366	 * the count of rows
367	 */
368	if ($lld_ruleid == 0) {
369		// applications
370		$applications = new CSpan([
371			new CLink(_('Applications'), 'applications.php?hostid='.$db_host['hostid']),
372			CViewHelper::showNum($db_host['applications'])
373		]);
374		if ($current_element == 'applications') {
375			$applications->addClass(ZBX_STYLE_SELECTED);
376		}
377		$list->addItem($applications);
378
379		// items
380		$items = new CSpan([
381			new CLink(_('Items'), 'items.php?filter_set=1&hostid='.$db_host['hostid']),
382			CViewHelper::showNum($db_host['items'])
383		]);
384		if ($current_element == 'items') {
385			$items->addClass(ZBX_STYLE_SELECTED);
386		}
387		$list->addItem($items);
388
389		// triggers
390		$triggers = new CSpan([
391			new CLink(_('Triggers'), 'triggers.php?hostid='.$db_host['hostid']),
392			CViewHelper::showNum($db_host['triggers'])
393		]);
394		if ($current_element == 'triggers') {
395			$triggers->addClass(ZBX_STYLE_SELECTED);
396		}
397		$list->addItem($triggers);
398
399		// graphs
400		$graphs = new CSpan([
401			new CLink(_('Graphs'), 'graphs.php?hostid='.$db_host['hostid']),
402			CViewHelper::showNum($db_host['graphs'])
403		]);
404		if ($current_element == 'graphs') {
405			$graphs->addClass(ZBX_STYLE_SELECTED);
406		}
407		$list->addItem($graphs);
408
409		// screens
410		if ($is_template) {
411			$screens = new CSpan([
412				new CLink(_('Screens'), 'screenconf.php?templateid='.$db_host['hostid']),
413				CViewHelper::showNum($db_host['screens'])
414			]);
415			if ($current_element == 'screens') {
416				$screens->addClass(ZBX_STYLE_SELECTED);
417			}
418			$list->addItem($screens);
419		}
420
421		// discovery rules
422		$lld_rules = new CSpan([
423			new CLink(_('Discovery rules'), 'host_discovery.php?hostid='.$db_host['hostid']),
424			CViewHelper::showNum($db_host['discoveries'])
425		]);
426		if ($current_element == 'discoveries') {
427			$lld_rules->addClass(ZBX_STYLE_SELECTED);
428		}
429		$list->addItem($lld_rules);
430
431		// web scenarios
432		$http_tests = new CSpan([
433			new CLink(_('Web scenarios'), 'httpconf.php?hostid='.$db_host['hostid']),
434			CViewHelper::showNum($db_host['httpTests'])
435		]);
436		if ($current_element == 'web') {
437			$http_tests->addClass(ZBX_STYLE_SELECTED);
438		}
439		$list->addItem($http_tests);
440	}
441	else {
442		$discovery_rule = (new CSpan())->addItem(
443			new CLink(
444				CHtml::encode($db_discovery_rule['name']),
445				'host_discovery.php?form=update&itemid='.$db_discovery_rule['itemid']
446			)
447		);
448
449		if ($current_element == 'discoveries') {
450			$discovery_rule->addClass(ZBX_STYLE_SELECTED);
451		}
452
453		$list->addItem([
454			(new CSpan())->addItem(
455				new CLink(_('Discovery list'), 'host_discovery.php?hostid='.$db_host['hostid'].url_param('groupid'))
456			),
457			'/',
458			$discovery_rule
459		]);
460
461		// item prototypes
462		$item_prototypes = new CSpan([
463			new CLink(_('Item prototypes'), 'disc_prototypes.php?parent_discoveryid='.$db_discovery_rule['itemid']),
464			CViewHelper::showNum($db_discovery_rule['items'])
465		]);
466		if ($current_element == 'items') {
467			$item_prototypes->addClass(ZBX_STYLE_SELECTED);
468		}
469		$list->addItem($item_prototypes);
470
471		// trigger prototypes
472		$trigger_prototypes = new CSpan([
473			new CLink(_('Trigger prototypes'),
474				'trigger_prototypes.php?parent_discoveryid='.$db_discovery_rule['itemid']
475			),
476			CViewHelper::showNum($db_discovery_rule['triggers'])
477		]);
478		if ($current_element == 'triggers') {
479			$trigger_prototypes->addClass(ZBX_STYLE_SELECTED);
480		}
481		$list->addItem($trigger_prototypes);
482
483		// graph prototypes
484		$graph_prototypes = new CSpan([
485			new CLink(_('Graph prototypes'), 'graphs.php?parent_discoveryid='.$db_discovery_rule['itemid']),
486			CViewHelper::showNum($db_discovery_rule['graphs'])
487		]);
488		if ($current_element == 'graphs') {
489			$graph_prototypes->addClass(ZBX_STYLE_SELECTED);
490		}
491		$list->addItem($graph_prototypes);
492
493		// host prototypes
494		if ($db_host['flags'] == ZBX_FLAG_DISCOVERY_NORMAL) {
495			$host_prototypes = new CSpan([
496				new CLink(_('Host prototypes'), 'host_prototypes.php?parent_discoveryid='.$db_discovery_rule['itemid']),
497				CViewHelper::showNum($db_discovery_rule['hostPrototypes'])
498			]);
499			if ($current_element == 'hosts') {
500				$host_prototypes->addClass(ZBX_STYLE_SELECTED);
501			}
502			$list->addItem($host_prototypes);
503		}
504	}
505
506	return $list;
507}
508
509/**
510 * Create CDiv with sysmap information
511 *
512 * @param int    $sysmapid
513 * @param string $name
514 *
515 * @return object
516 */
517function get_header_sysmap_table($sysmapid, $name, $fullscreen, $severity_min) {
518	$list = (new CList())
519		->addClass(ZBX_STYLE_OBJECT_GROUP)
520		->addItem([
521			(new CSpan())->addItem(new CLink(_('All maps'), 'sysmaps.php')),
522			'/',
523			(new CSpan())
524				->addClass(ZBX_STYLE_SELECTED)
525				->addItem(
526					new CLink($name, 'zabbix.php?action=map.view&sysmapid='.$sysmapid.'&fullscreen='.$fullscreen.
527						'&severity_min='.$severity_min
528					)
529				)
530		]);
531
532	// get map parent maps
533	$parent_sysmaps = get_parent_sysmaps($sysmapid);
534	if ($parent_sysmaps) {
535		$hor_list = new CHorList();
536
537		foreach ($parent_sysmaps as $parent_sysmap) {
538			$hor_list->addItem(
539				new CLink($parent_sysmap['name'], 'zabbix.php?action=map.view'.
540					'&sysmapid='.$parent_sysmap['sysmapid'].'&fullscreen='.$fullscreen.'&severity_min='.$severity_min
541				)
542			);
543		}
544
545		$list->addItem(new CSpan(_('Upper level maps').':'));
546		$list->addItem($hor_list);
547	}
548
549	return $list;
550}
551
552/**
553 * Renders a form footer with the given buttons.
554 *
555 * @param CButtonInterface 		$main_button	main button that will be displayed on the left
556 * @param CButtonInterface[] 	$other_buttons
557 *
558 * @return CDiv
559 *
560 * @throws InvalidArgumentException	if an element of $other_buttons contain something other than CButtonInterface
561 */
562function makeFormFooter(CButtonInterface $main_button = null, array $other_buttons = []) {
563	foreach ($other_buttons as $other_button) {
564		$other_button->addClass(ZBX_STYLE_BTN_ALT);
565	}
566
567	if ($main_button !== null) {
568		array_unshift($other_buttons, $main_button);
569	}
570
571	return (new CList())
572		->addClass(ZBX_STYLE_TABLE_FORMS)
573		->addItem([
574			(new CDiv())->addClass(ZBX_STYLE_TABLE_FORMS_TD_LEFT),
575			(new CDiv($other_buttons))
576				->addClass(ZBX_STYLE_TABLE_FORMS_TD_RIGHT)
577				->addClass('tfoot-buttons')
578		]);
579}
580
581/**
582 * Returns zbx, snmp, jmx, ipmi availability status icons and the discovered host lifetime indicator.
583 *
584 * @param array $host		an array of host data
585 *
586 * @return CDiv
587 */
588function getHostAvailabilityTable($host) {
589	$container = (new CDiv())->addClass(ZBX_STYLE_STATUS_CONTAINER);
590
591	foreach (['zbx' => '', 'snmp' => 'snmp_', 'jmx' => 'jmx_', 'ipmi' => 'ipmi_'] as $type => $prefix) {
592		switch ($host[$prefix.'available']) {
593			case HOST_AVAILABLE_TRUE:
594				$ai = (new CSpan($type))->addClass(ZBX_STYLE_STATUS_GREEN);
595				break;
596			case HOST_AVAILABLE_FALSE:
597				$ai = (new CSpan($type))->addClass(ZBX_STYLE_STATUS_RED);
598
599				if ($host[$prefix.'error'] !== '') {
600					$ai
601						->addClass(ZBX_STYLE_CURSOR_POINTER)
602						->setHint($host[$prefix.'error'], ZBX_STYLE_RED);
603				}
604
605				break;
606			case HOST_AVAILABLE_UNKNOWN:
607				$ai = (new CSpan($type))->addClass(ZBX_STYLE_STATUS_GREY);
608				break;
609		}
610		$container->addItem($ai);
611	}
612
613	return $container;
614}
615
616/**
617 * Returns the discovered host group lifetime indicator.
618 *
619 * @param string $current_time	current Unix timestamp
620 * @param array  $ts_delete		deletion timestamp of the host group
621 *
622 * @return CDiv
623 */
624function getHostGroupLifetimeIndicator($current_time, $ts_delete) {
625	// Check if the element should've been deleted in the past.
626	if ($current_time > $ts_delete) {
627		$warning = _(
628			'The host group is not discovered anymore and will be deleted the next time discovery rule is processed.'
629		);
630	}
631	else {
632		$warning = _s(
633			'The host group is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).',
634			zbx_date2age($ts_delete),
635			zbx_date2str(DATE_FORMAT, $ts_delete),
636			zbx_date2str(TIME_FORMAT, $ts_delete)
637		);
638	}
639
640	return makeWarningIcon($warning);
641}
642
643/**
644 * Returns the discovered host lifetime indicator.
645 *
646 * @param string $current_time	current Unix timestamp
647 * @param array  $ts_delete		deletion timestamp of the host
648 *
649 * @return CDiv
650 */
651function getHostLifetimeIndicator($current_time, $ts_delete) {
652	// Check if the element should've been deleted in the past.
653	if ($current_time > $ts_delete) {
654		$warning = _(
655			'The host is not discovered anymore and will be deleted the next time discovery rule is processed.'
656		);
657	}
658	else {
659		$warning = _s(
660			'The host is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).',
661			zbx_date2age($ts_delete),
662			zbx_date2str(DATE_FORMAT, $ts_delete),
663			zbx_date2str(TIME_FORMAT, $ts_delete)
664		);
665	}
666
667	return makeWarningIcon($warning);
668}
669
670/**
671 * Returns the discovered application lifetime indicator.
672 *
673 * @param string $current_time	current Unix timestamp
674 * @param array  $ts_delete		deletion timestamp of the application
675 *
676 * @return CDiv
677 */
678function getApplicationLifetimeIndicator($current_time, $ts_delete) {
679	// Check if the element should've been deleted in the past.
680	if ($current_time > $ts_delete) {
681		$warning = _(
682			'The application is not discovered anymore and will be deleted the next time discovery rule is processed.'
683		);
684	}
685	else {
686		$warning = _s(
687			'The application is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).',
688			zbx_date2age($ts_delete),
689			zbx_date2str(DATE_FORMAT, $ts_delete),
690			zbx_date2str(TIME_FORMAT, $ts_delete)
691		);
692	}
693
694	return makeWarningIcon($warning);
695}
696
697/**
698 * Returns the discovered item lifetime indicator.
699 *
700 * @param string $current_time	current Unix timestamp
701 * @param array  $ts_delete		deletion timestamp of the item
702 *
703 * @return CDiv
704 */
705function getItemLifetimeIndicator($current_time, $ts_delete) {
706	// Check if the element should've been deleted in the past.
707	if ($current_time > $ts_delete) {
708		$warning = _(
709			'The item is not discovered anymore and will be deleted the next time discovery rule is processed.'
710		);
711	}
712	else {
713		$warning = _s(
714			'The item is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).',
715			zbx_date2age($ts_delete),
716			zbx_date2str(DATE_FORMAT, $ts_delete),
717			zbx_date2str(TIME_FORMAT, $ts_delete)
718		);
719	}
720
721	return makeWarningIcon($warning);
722}
723
724/**
725 * Create array with all inputs required for date selection and calendar.
726 *
727 * @param string      $name
728 * @param int|array   $date unix timestamp/date array(Y,m,d,H,i)
729 * @param string|null $relatedCalendar name of the calendar which must be closed when this calendar opens
730 *
731 * @return array
732 */
733function createDateSelector($name, $date, $relatedCalendar = null) {
734	$onClick = 'var pos = getPosition(this); pos.top += 10; pos.left += 16; CLNDR["'.$name.
735		'_calendar"].clndr.clndrshow(pos.top, pos.left);';
736	if ($relatedCalendar) {
737		$onClick .= ' CLNDR["'.$relatedCalendar.'_calendar"].clndr.clndrhide();';
738	}
739
740	if (is_array($date)) {
741		$y = $date['y'];
742		$m = $date['m'];
743		$d = $date['d'];
744		$h = $date['h'];
745		$i = $date['i'];
746	}
747	else {
748		$y = date('Y', $date);
749		$m = date('m', $date);
750		$d = date('d', $date);
751		$h = date('H', $date);
752		$i = date('i', $date);
753	}
754
755	$fields = [
756		(new CNumericBox($name.'_year', $y, 4))
757			->setWidth(ZBX_TEXTAREA_4DIGITS_WIDTH)
758			->setAttribute('placeholder', _('yyyy')),
759		(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
760		'-',
761		(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
762		(new CTextBox($name.'_month', $m, false, 2))
763			->setWidth(ZBX_TEXTAREA_2DIGITS_WIDTH)
764			->addStyle('text-align: right;')
765			->setAttribute('placeholder', _('mm'))
766			->onChange('validateDatePartBox(this, 1, 12, 2);'),
767		(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
768		'-',
769		(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
770		(new CTextBox($name.'_day', $d, false, 2))
771			->setWidth(ZBX_TEXTAREA_2DIGITS_WIDTH)
772			->addStyle('text-align: right;')
773			->setAttribute('placeholder', _('dd'))
774			->onChange('validateDatePartBox(this, 1, 31, 2);'),
775		(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
776		(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
777		(new CTextBox($name.'_hour', $h, false, 2))
778			->setWidth(ZBX_TEXTAREA_2DIGITS_WIDTH)
779			->addStyle('text-align: right;')
780			->setAttribute('placeholder', _('hh'))
781			->onChange('validateDatePartBox(this, 0, 23, 2);'),
782		(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
783		':',
784		(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
785		(new CTextBox($name.'_minute', $i, false, 2))
786			->setWidth(ZBX_TEXTAREA_2DIGITS_WIDTH)
787			->addStyle('text-align: right;')
788			->setAttribute('placeholder', _('mm'))
789			->onChange('validateDatePartBox(this, 0, 59, 2);'),
790		(new CButton())
791			->addClass(ZBX_STYLE_ICON_CAL)
792			->onClick($onClick)
793	];
794
795	zbx_add_post_js('create_calendar(null,'.
796		'["'.$name.'_day","'.$name.'_month","'.$name.'_year","'.$name.'_hour","'.$name.'_minute"],'.
797		'"'.$name.'_calendar",'.
798		'"'.$name.'");'
799	);
800
801	return $fields;
802}
803
804/**
805 * Renders a page footer.
806 *
807 * @param bool $with_logo
808 * @param bool $with_version
809 *
810 * @return CDiv
811 */
812function makePageFooter($with_version = true)
813{
814	return (new CDiv([
815		$with_version ? 'Zabbix '.ZABBIX_VERSION.'. ' : null,
816		'&copy; '.ZABBIX_COPYRIGHT_FROM.'&ndash;'.ZABBIX_COPYRIGHT_TO.', ',
817		(new CLink('Zabbix SIA', 'http://www.zabbix.com/'))
818			->addClass(ZBX_STYLE_GREY)
819			->addClass(ZBX_STYLE_LINK_ALT)
820			->setAttribute('target', '_blank')
821	]))->addClass(ZBX_STYLE_FOOTER);
822}
823
824/**
825 * Renders a drop-down menu for the Administration->General section.
826 *
827 * @param string $selected
828 *
829 * @return CComboBox
830 */
831function makeAdministrationGeneralMenu($selected)
832{
833	return new CComboBox('configDropDown', $selected, 'redirect(this.options[this.selectedIndex].value);', [
834		'adm.gui.php' => _('GUI'),
835		'adm.housekeeper.php' => _('Housekeeping'),
836		'adm.images.php' => _('Images'),
837		'adm.iconmapping.php' => _('Icon mapping'),
838		'adm.regexps.php' => _('Regular expressions'),
839		'adm.macros.php' => _('Macros'),
840		'adm.valuemapping.php' => _('Value mapping'),
841		'adm.workingtime.php' => _('Working time'),
842		'adm.triggerseverities.php' => _('Trigger severities'),
843		'adm.triggerdisplayoptions.php' => _('Trigger displaying options'),
844		'adm.other.php' => _('Other')
845	]);
846}
847
848/**
849 * Renders an error icon like [x] with error message
850 *
851 * @param string $error
852 *
853 * @return CSpan
854 */
855function makeErrorIcon($error)
856{
857	return (new CSpan(bold('&times;')))
858		->addClass(ZBX_STYLE_STATUS_RED)
859		->addClass(ZBX_STYLE_CURSOR_POINTER)
860		->setHint($error, ZBX_STYLE_RED);
861}
862
863/**
864 * Renders an unknown icon like [?] with error message
865 *
866 * @param string $error
867 *
868 * @return CSpan
869 */
870function makeUnknownIcon($error)
871{
872	return (new CSpan(bold('?')))
873		->addClass(ZBX_STYLE_STATUS_GREY)
874		->addClass(ZBX_STYLE_CURSOR_POINTER)
875		->setHint($error, ZBX_STYLE_RED);
876}
877
878/**
879 * Renders a warning icon like [!] with error message
880 *
881 * @param string $error
882 *
883 * @return CSpan
884 */
885function makeWarningIcon($error)
886{
887	return (new CSpan(bold('!')))
888		->addClass(ZBX_STYLE_STATUS_YELLOW)
889		->addClass(ZBX_STYLE_CURSOR_POINTER)
890		->setHint($error);
891}
892
893/**
894 * Renders a debug button
895 *
896 * @return CButton
897 */
898function makeDebugButton()
899{
900	return (new CDiv(
901		(new CLink(_('Debug'), '#debug'))
902			->onClick("javascript: if (!isset('state', this)) { this.state = 'none'; }".
903				"this.state = (this.state == 'none' ? 'block' : 'none');".
904				"jQuery(this)".
905					".text(this.state == 'none' ? ".CJs::encodeJson(_('Debug'))." : ".CJs::encodeJson(_('Hide debug')).")".
906					".blur();".
907				"showHideByName('zbx_debug_info', this.state);"
908			)
909	))->addClass(ZBX_STYLE_BTN_DEBUG);
910}
911
912/**
913 * Returns css for trigger severity backgrounds
914 *
915 * @param array $config
916 * @param array $config[severity_color_0]
917 * @param array $config[severity_color_1]
918 * @param array $config[severity_color_2]
919 * @param array $config[severity_color_3]
920 * @param array $config[severity_color_4]
921 * @param array $config[severity_color_5]
922 *
923 * @return string
924 */
925function getTriggerSeverityCss($config)
926{
927	$severities = [
928		ZBX_STYLE_NA_BG => $config['severity_color_0'],
929		ZBX_STYLE_INFO_BG => $config['severity_color_1'],
930		ZBX_STYLE_WARNING_BG => $config['severity_color_2'],
931		ZBX_STYLE_AVERAGE_BG => $config['severity_color_3'],
932		ZBX_STYLE_HIGH_BG => $config['severity_color_4'],
933		ZBX_STYLE_DISASTER_BG => $config['severity_color_5']
934	];
935
936	$css = '';
937
938	foreach ($severities as $class => $color) {
939		$css .= '.'.$class.', .'.$class.' input[type="radio"]:checked + label { background-color: #'.$color.' }'."\n";
940	}
941
942	return $css;
943}
944