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
22class CControllerPopupTriggerExpr extends CController {
23
24	private $metrics = [];
25	private $param1SecCount = [];
26	private $param1Period = [];
27	private $param1Sec = [];
28	private $param1Str = [];
29	private $param2SecCount = [];
30	private $param2SecMode = [];
31	private $param3SecVal = [];
32	private $param_find = [];
33	private $param3SecPercent = [];
34	private $paramForecast = [];
35	private $paramTimeleft = [];
36	private $allowedTypesAny = [];
37	private $allowedTypesNumeric = [];
38	private $allowedTypesStr = [];
39	private $allowedTypesLog = [];
40	private $allowedTypesInt = [];
41	private $functions = [];
42	private $operators = ['=', '<>', '>', '<', '>=', '<='];
43	private $period_optional = [];
44
45	protected function init() {
46		$this->disableSIDvalidation();
47
48		$this->metrics = [
49			PARAM_TYPE_TIME => _('Time'),
50			PARAM_TYPE_COUNTS => _('Count')
51		];
52
53		/*
54		 * C - caption
55		 * T - type
56		 * M - metrics
57		 * A - asterisk
58		 */
59		$this->param1SecCount = [
60			'last' => [
61				'C' => _('Last of').' (T)',
62				'T' => T_ZBX_INT,
63				'M' => $this->metrics,
64				'A' => true
65			],
66			'shift' => [
67				'C' => _('Time shift'),
68				'T' => T_ZBX_INT,
69				'A' => false
70			]
71		];
72
73		$this->period_optional = [
74			'last' => [
75				'C' => _('Last of').' (T)',
76				'T' => T_ZBX_INT,
77				'M' => $this->metrics,
78				'A' => false
79			],
80			'shift' => [
81				'C' => _('Time shift'),
82				'T' => T_ZBX_INT,
83				'A' => false
84			]
85		];
86
87		$this->param1Period = [
88			'last' => [
89				'C' => _('Last of').' (T)',
90				'T' => T_ZBX_INT,
91				'A' => true
92			],
93			'period_shift' => [
94				'C' => _('Period shift'),
95				'T' => T_ZBX_INT,
96				'A' => true
97			]
98		];
99
100		$this->param1Sec = [
101			'last' => [
102				'C' => _('Last of').' (T)',
103				'T' => T_ZBX_INT,
104				'A' => true
105			]
106		];
107
108		$this->param1Str = [
109			'pattern' => [
110				'C' => 'V',
111				'T' => T_ZBX_STR,
112				'A' => false
113			]
114		];
115
116		$this->param2SecCount = [
117			'pattern' => [
118				'C' => 'V',
119				'T' => T_ZBX_STR,
120				'A' => false
121			],
122			'last' => [
123				'C' => _('Last of').' (T)',
124				'T' => T_ZBX_INT,
125				'M' => $this->metrics,
126				'A' => false
127			]
128		];
129
130		$this->param2SecMode = [
131			'last' => [
132				'C' => _('Last of').' (T)',
133				'T' => T_ZBX_INT,
134				'A' => true
135			],
136			'mode' => [
137				'C' => 'Mode',
138				'T' => T_ZBX_STR,
139				'A' => false
140			]
141		];
142
143		$this->param3SecVal = [
144			'last' => [
145				'C' => _('Last of').' (T)',
146				'T' => T_ZBX_INT,
147				'M' => $this->metrics,
148				'A' => true
149			],
150			'shift' => [
151				'C' => _('Time shift'),
152				'T' => T_ZBX_INT,
153				'A' => false
154			],
155			'o' => [
156				'C' => 'O',
157				'T' => T_ZBX_STR,
158				'A' => false
159			],
160			'v' => [
161				'C' => 'V',
162				'T' => T_ZBX_STR,
163				'A' => false
164			]
165		];
166
167		$this->param_find = [
168			'o' => [
169				'C' => 'O',
170				'T' => T_ZBX_STR,
171				'A' => false
172			],
173			'v' => [
174				'C' => 'V',
175				'T' => T_ZBX_STR,
176				'A' => false
177			]
178		];
179
180		$this->param3SecPercent = [
181			'last' => [
182				'C' => _('Last of').' (T)',
183				'T' => T_ZBX_INT,
184				'M' => $this->metrics,
185				'A' => true
186			],
187			'shift' => [
188				'C' => _('Time shift'),
189				'T' => T_ZBX_INT,
190				'A' => false
191			],
192			'p' => [
193				'C' => _('Percentage').' (P)',
194				'T' => T_ZBX_DBL,
195				'A' => true
196			]
197		];
198
199		$this->paramForecast = [
200			'last' => [
201				'C' => _('Last of').' (T)',
202				'T' => T_ZBX_INT,
203				'M' => $this->metrics,
204				'A' => true
205			],
206			'shift' => [
207				'C' => _('Time shift'),
208				'T' => T_ZBX_INT,
209				'A' => false
210			],
211			'time' => [
212				'C' => _('Time').' (t)',
213				'T' => T_ZBX_INT,
214				'A' => true
215			],
216			'fit' => [
217				'C' => _('Fit'),
218				'T' => T_ZBX_STR,
219				'A' => false
220			],
221			'mode' => [
222				'C' => _('Mode'),
223				'T' => T_ZBX_STR,
224				'A' => false
225			]
226		];
227
228		$this->paramTimeleft = [
229			'last' => [
230				'C' => _('Last of').' (T)',
231				'T' => T_ZBX_INT,
232				'M' => $this->metrics,
233				'A' => true
234			],
235			'shift' => [
236				'C' => _('Time shift'),
237				'T' => T_ZBX_INT,
238				'A' => false
239			],
240			't' => [
241				'C' => _('Threshold'),
242				'T' => T_ZBX_DBL,
243				'A' => true
244			],
245			'fit' => [
246				'C' => _('Fit'),
247				'T' => T_ZBX_STR,
248				'A' => false
249			]
250		];
251
252		$this->allowedTypesAny = [
253			ITEM_VALUE_TYPE_FLOAT => 1,
254			ITEM_VALUE_TYPE_STR => 1,
255			ITEM_VALUE_TYPE_LOG => 1,
256			ITEM_VALUE_TYPE_UINT64 => 1,
257			ITEM_VALUE_TYPE_TEXT => 1
258		];
259
260		$this->allowedTypesNumeric = [
261			ITEM_VALUE_TYPE_FLOAT => 1,
262			ITEM_VALUE_TYPE_UINT64 => 1
263		];
264
265		$this->allowedTypesStr = [
266			ITEM_VALUE_TYPE_STR => 1,
267			ITEM_VALUE_TYPE_LOG => 1,
268			ITEM_VALUE_TYPE_TEXT => 1
269		];
270
271		$this->allowedTypesLog = [
272			ITEM_VALUE_TYPE_LOG => 1
273		];
274
275		$this->allowedTypesInt = [
276			ITEM_VALUE_TYPE_UINT64 => 1
277		];
278
279		$this->functions = [
280			'abs' => [
281				'types' => [ZBX_FUNCTION_TYPE_MATH],
282				'description' => _('abs() - Absolute value'),
283				'allowed_types' => $this->allowedTypesAny,
284				'operators' => $this->operators
285			],
286			'acos' => [
287				'types' => [ZBX_FUNCTION_TYPE_MATH],
288				'description' => _('acos() - The arccosine of a value as an angle, expressed in radians'),
289				'params' => $this->param1SecCount,
290				'allowed_types' => $this->allowedTypesNumeric,
291				'operators' => $this->operators
292			],
293			'ascii' => [
294				'types' => [ZBX_FUNCTION_TYPE_STRING],
295				'description' => _('ascii() - Returns the ASCII code of the leftmost character of the value'),
296				'params' => $this->param1SecCount,
297				'allowed_types' => $this->allowedTypesStr,
298				'operators' => $this->operators
299			],
300			'asin' => [
301				'types' => [ZBX_FUNCTION_TYPE_MATH],
302				'description' => _('asin() - The arcsine of a value as an angle, expressed in radians'),
303				'params' => $this->param1SecCount,
304				'allowed_types' => $this->allowedTypesNumeric,
305				'operators' => $this->operators
306			],
307			'atan' => [
308				'types' => [ZBX_FUNCTION_TYPE_MATH],
309				'description' => _('atan() - The arctangent of a value as an angle, expressed in radians'),
310				'params' => $this->param1SecCount,
311				'allowed_types' => $this->allowedTypesNumeric,
312				'operators' => $this->operators
313			],
314			'atan2' => [
315				'types' => [ZBX_FUNCTION_TYPE_MATH],
316				'description' => _('atan2() - The arctangent of the ordinate (exprue) and abscissa coordinates specified as an angle, expressed in radians'),
317				'params' => $this->param1SecCount + [
318					'abscissa' => [
319						'C' => _('Abscissa'),
320						'T' => T_ZBX_STR,
321						'A' => true
322					]
323				],
324				'allowed_types' => $this->allowedTypesNumeric,
325				'operators' => $this->operators
326			],
327			'avg' => [
328				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE, ZBX_FUNCTION_TYPE_MATH],
329				'description' => _('avg() - Average value of a period T'),
330				'params' => $this->param1SecCount,
331				'allowed_types' => $this->allowedTypesNumeric,
332				'operators' => $this->operators
333			],
334			'between' => [
335				'types' => [ZBX_FUNCTION_TYPE_OPERATOR],
336				'description' => _('between() - Checks if a value belongs to the given range (1 - in range, 0 - otherwise)'),
337				'params' => $this->param1SecCount + [
338					'min' => [
339						'C' => _('Min'),
340						'T' => T_ZBX_STR,
341						'A' => true
342					],
343					'max' => [
344						'C' => _('Max'),
345						'T' => T_ZBX_STR,
346						'A' => true
347					]
348				],
349				'allowed_types' => $this->allowedTypesNumeric,
350				'operators' => ['=', '<>']
351			],
352			'bitand' => [
353				'types' => [ZBX_FUNCTION_TYPE_BITWISE],
354				'description' => _('bitand() - Bitwise AND'),
355				'params' => $this->param1SecCount + [
356					'mask' => [
357						'C' => _('Mask'),
358						'T' => T_ZBX_STR,
359						'A' => true
360					]
361				],
362				'allowed_types' => $this->allowedTypesInt,
363				'operators' => $this->operators
364			],
365			'bitlength' => [
366				'types' => [ZBX_FUNCTION_TYPE_STRING],
367				'description' => _('bitlength() - Returns the length in bits'),
368				'params' => $this->param1SecCount,
369				'allowed_types' => $this->allowedTypesAny,
370				'operators' => $this->operators
371			],
372			'bitlshift' => [
373				'types' => [ZBX_FUNCTION_TYPE_BITWISE],
374				'description' => _('bitlshift() - Bitwise shift left'),
375				'params' => $this->param1SecCount + [
376					'bits' => [
377						'C' => _('Bits to shift'),
378						'T' => T_ZBX_STR,
379						'A' => true
380					]
381				],
382				'allowed_types' => $this->allowedTypesInt,
383				'operators' => $this->operators
384			],
385			'bitnot' => [
386				'types' => [ZBX_FUNCTION_TYPE_BITWISE],
387				'description' => _('bitnot() - Bitwise NOT'),
388				'params' => $this->param1SecCount,
389				'allowed_types' => $this->allowedTypesInt,
390				'operators' => $this->operators
391			],
392			'bitor' => [
393				'types' => [ZBX_FUNCTION_TYPE_BITWISE],
394				'description' => _('bitor() - Bitwise OR'),
395				'params' => $this->param1SecCount + [
396					'mask' => [
397						'C' => _('Mask'),
398						'T' => T_ZBX_STR,
399						'A' => true
400					]
401				],
402				'allowed_types' => $this->allowedTypesInt,
403				'operators' => $this->operators
404			],
405			'bitrshift' => [
406				'types' => [ZBX_FUNCTION_TYPE_BITWISE],
407				'description' => _('bitrshift() - Bitwise shift right'),
408				'params' => $this->param1SecCount + [
409					'bits' => [
410						'C' => _('Bits to shift'),
411						'T' => T_ZBX_STR,
412						'A' => true
413					]
414				],
415				'allowed_types' => $this->allowedTypesInt,
416				'operators' => $this->operators
417			],
418			'bitxor' => [
419				'types' => [ZBX_FUNCTION_TYPE_BITWISE],
420				'description' => _('bitxor() - Bitwise exclusive OR'),
421				'params' => $this->param1SecCount + [
422					'mask' => [
423						'C' => _('Mask'),
424						'T' => T_ZBX_STR,
425						'A' => true
426					]
427				],
428				'allowed_types' => $this->allowedTypesInt,
429				'operators' => $this->operators
430			],
431			'bytelength' => [
432				'types' => [ZBX_FUNCTION_TYPE_STRING],
433				'description' => _('bytelength() - Returns the length in bytes'),
434				'params' => $this->param1SecCount,
435				'allowed_types' => $this->allowedTypesAny,
436				'operators' => $this->operators
437			],
438			'cbrt' => [
439				'types' => [ZBX_FUNCTION_TYPE_MATH],
440				'description' => _('cbrt() - Cube root'),
441				'params' => $this->param1SecCount,
442				'allowed_types' => $this->allowedTypesNumeric,
443				'operators' => $this->operators
444			],
445			'ceil' => [
446				'types' => [ZBX_FUNCTION_TYPE_MATH],
447				'description' => _('ceil() - Rounds up to the nearest greater integer'),
448				'params' => $this->param1SecCount,
449				'allowed_types' => $this->allowedTypesNumeric,
450				'operators' => $this->operators
451			],
452			'change' => [
453				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
454				'description' => _('change() - Difference between last and previous value'),
455				'allowed_types' => $this->allowedTypesAny,
456				'operators' => $this->operators
457			],
458			'char' => [
459				'types' => [ZBX_FUNCTION_TYPE_STRING],
460				'description' => _('char() - Returns the character which represents the given ASCII code'),
461				'params' => $this->param1SecCount,
462				'allowed_types' => $this->allowedTypesInt,
463				'operators' => $this->operators
464			],
465			'concat' => [
466				'types' => [ZBX_FUNCTION_TYPE_STRING],
467				'description' => _('concat() - Returns a string that is the result of concatenating value to string'),
468				'params' => $this->param1SecCount + [
469					'string' => [
470						'C' => _('String'),
471						'T' => T_ZBX_STR,
472						'A' => true
473					]
474				],
475				'allowed_types' => $this->allowedTypesAny,
476				'operators' => $this->operators
477			],
478			'cos' => [
479				'types' => [ZBX_FUNCTION_TYPE_MATH],
480				'description' => _('cos() - The cosine of a value, where the value is an angle expressed in radians'),
481				'params' => $this->param1SecCount,
482				'allowed_types' => $this->allowedTypesNumeric,
483				'operators' => $this->operators
484			],
485			'cosh' => [
486				'types' => [ZBX_FUNCTION_TYPE_MATH],
487				'description' => _('cosh() - The hyperbolic cosine of a value'),
488				'params' => $this->param1SecCount,
489				'allowed_types' => $this->allowedTypesNumeric,
490				'operators' => $this->operators
491			],
492			'cot' => [
493				'types' => [ZBX_FUNCTION_TYPE_MATH],
494				'description' => _('cot() - The cotangent of a value, where the value is an angle expressed in radians'),
495				'params' => $this->param1SecCount,
496				'allowed_types' => $this->allowedTypesNumeric,
497				'operators' => $this->operators
498			],
499			'count' => [
500				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
501				'description' => _('count() - Number of successfully retrieved values V (which fulfill operator O) for period T'),
502				'params' => $this->param3SecVal,
503				'allowed_types' => $this->allowedTypesAny,
504				'operators' => $this->operators
505			],
506			'countunique' => [
507				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
508				'description' => _('countunique() - The number of unique values'),
509				'params' => $this->param3SecVal,
510				'allowed_types' => $this->allowedTypesAny,
511				'operators' => $this->operators
512			],
513			'date' => [
514				'types' => [ZBX_FUNCTION_TYPE_DATE_TIME],
515				'description' => _('date() - Current date'),
516				'allowed_types' => $this->allowedTypesAny,
517				'operators' => $this->operators
518			],
519			'dayofmonth' => [
520				'types' => [ZBX_FUNCTION_TYPE_DATE_TIME],
521				'description' => _('dayofmonth() - Day of month'),
522				'allowed_types' => $this->allowedTypesAny,
523				'operators' => $this->operators
524			],
525			'dayofweek' => [
526				'types' => [ZBX_FUNCTION_TYPE_DATE_TIME],
527				'description' => _('dayofweek() - Day of week'),
528				'allowed_types' => $this->allowedTypesAny,
529				'operators' => $this->operators
530			],
531			'degrees' => [
532				'types' => [ZBX_FUNCTION_TYPE_MATH],
533				'description' => _('degrees() - Converts a value from radians to degrees'),
534				'params' => $this->param1SecCount,
535				'allowed_types' => $this->allowedTypesNumeric,
536				'operators' => $this->operators
537			],
538			'e' => [
539				'types' => [ZBX_FUNCTION_TYPE_MATH],
540				'description' => _("e() - Returns Euler's number"),
541				'allowed_types' => $this->allowedTypesAny
542			],
543			'exp' => [
544				'types' => [ZBX_FUNCTION_TYPE_MATH],
545				'description' => _("exp() - Euler's number at a power of a value"),
546				'params' => $this->param1SecCount,
547				'allowed_types' => $this->allowedTypesNumeric,
548				'operators' => $this->operators
549			],
550			'expm1' => [
551				'types' => [ZBX_FUNCTION_TYPE_MATH],
552				'description' => _("expm1() - Euler's number at a power of a value minus 1"),
553				'params' => $this->param1SecCount,
554				'allowed_types' => $this->allowedTypesNumeric,
555				'operators' => $this->operators
556			],
557			'find' => [
558				'types' => [ZBX_FUNCTION_TYPE_STRING],
559				'description' => _('find() - Check occurrence of pattern V (which fulfill operator O) for period T (1 - match, 0 - no match)'),
560				'params' => $this->period_optional + $this->param_find,
561				'allowed_types' => $this->allowedTypesAny,
562				'operators' => ['=', '<>']
563			],
564			'first' => [
565				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
566				'description' => _('first() - The oldest value in the specified time interval'),
567				'params' => $this->param1Sec + $this->period_optional,
568				'allowed_types' => $this->allowedTypesAny,
569				'operators' => $this->operators
570			],
571			'floor' => [
572				'types' => [ZBX_FUNCTION_TYPE_MATH],
573				'description' => _('floor() - Rounds down to the nearest smaller integer'),
574				'params' => $this->param1SecCount,
575				'allowed_types' => $this->allowedTypesNumeric,
576				'operators' => $this->operators
577			],
578			'forecast' => [
579				'types' => [ZBX_FUNCTION_TYPE_PREDICTION],
580				'description' => _('forecast() - Forecast for next t seconds based on period T'),
581				'params' => $this->paramForecast,
582				'allowed_types' => $this->allowedTypesNumeric,
583				'operators' => $this->operators
584			],
585			'fuzzytime' => [
586				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
587				'description' => _('fuzzytime() - Difference between item value (as timestamp) and Zabbix server timestamp is less than or equal to T seconds (1 - true, 0 - false)'),
588				'params' => $this->param1Sec,
589				'allowed_types' => $this->allowedTypesNumeric,
590				'operators' => ['=', '<>']
591			],
592			'in' => [
593				'types' => [ZBX_FUNCTION_TYPE_OPERATOR],
594				'description' => _('in() - Checks if a value equals to one of the listed values (1 - equals, 0 - otherwise)'),
595				'params' => $this->param1SecCount + [
596					'values' => [
597						'C' => _('Values'),
598						'T' => T_ZBX_STR,
599						'A' => true
600					]
601				],
602				'allowed_types' => $this->allowedTypesAny,
603				'operators' => ['=', '<>']
604			],
605			'insert' => [
606				'types' => [ZBX_FUNCTION_TYPE_STRING],
607				'description' => _('insert() - Inserts specified characters or spaces into a character string, beginning at a specified position in the string'),
608				'params' => $this->param1SecCount + [
609					'start' => [
610						'C' => _('Start'),
611						'T' => T_ZBX_STR,
612						'A' => true
613					],
614					'length' => [
615						'C' => _('Length'),
616						'T' => T_ZBX_STR,
617						'A' => true
618					],
619					'replace' => [
620						'C' => _('Replacement'),
621						'T' => T_ZBX_STR,
622						'A' => true
623					]
624				],
625				'allowed_types' => $this->allowedTypesStr,
626				'operators' => $this->operators
627			],
628			'kurtosis' => [
629				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
630				'description' => _('kurtosis() - Measures the "tailedness" of the probability distribution'),
631				'params' => $this->param1SecCount,
632				'allowed_types' => $this->allowedTypesNumeric,
633				'operators' => $this->operators
634			],
635			'last' => [
636				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
637				'description' => _('last() - Last (most recent) T value'),
638				'params' => $this->param1SecCount,
639				'allowed_types' => $this->allowedTypesAny,
640				'operators' => $this->operators
641			],
642			'left' => [
643				'types' => [ZBX_FUNCTION_TYPE_STRING],
644				'description' => _('left() - Returns the leftmost count characters'),
645				'params' => $this->param1SecCount + [
646					'count' => [
647						'C' => _('Count'),
648						'T' => T_ZBX_STR,
649						'A' => true
650					]
651				],
652				'allowed_types' => $this->allowedTypesStr,
653				'operators' => $this->operators
654			],
655			'length' => [
656				'types' => [ZBX_FUNCTION_TYPE_STRING],
657				'description' => _('length() - Length of last (most recent) T value in characters'),
658				'allowed_types' => $this->allowedTypesStr,
659				'operators' => $this->operators
660			],
661			'log' => [
662				'types' => [ZBX_FUNCTION_TYPE_MATH],
663				'description' => _('log() - Natural logarithm'),
664				'params' => $this->param1SecCount,
665				'allowed_types' => $this->allowedTypesNumeric,
666				'operators' => $this->operators
667			],
668			'log10' => [
669				'types' => [ZBX_FUNCTION_TYPE_MATH],
670				'description' => _('log10() - Decimal logarithm'),
671				'params' => $this->param1SecCount,
672				'allowed_types' => $this->allowedTypesNumeric,
673				'operators' => $this->operators
674			],
675			'logeventid' => [
676				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
677				'description' => _('logeventid() - Event ID of last log entry matching regular expression V for period T (1 - match, 0 - no match)'),
678				'params' => $this->period_optional + $this->param1Str,
679				'allowed_types' => $this->allowedTypesLog,
680				'operators' => ['=', '<>']
681			],
682			'logseverity' => [
683				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
684				'description' => _('logseverity() - Log severity of the last log entry for period T'),
685				'params' => $this->period_optional,
686				'allowed_types' => $this->allowedTypesLog,
687				'operators' => $this->operators
688			],
689			'logsource' => [
690				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
691				'description' => _('logsource() - Log source of the last log entry matching parameter V for period T (1 - match, 0 - no match)'),
692				'params' => $this->period_optional + $this->param1Str,
693				'allowed_types' => $this->allowedTypesLog,
694				'operators' => ['=', '<>']
695			],
696			'ltrim' => [
697				'types' => [ZBX_FUNCTION_TYPE_STRING],
698				'description' => _('ltrim() - Remove specified characters from the beginning of a string'),
699				'params' => $this->param1SecCount + [
700					'chars' => [
701						'C' => _('Chars'),
702						'T' => T_ZBX_STR,
703						'A' => false
704					]
705				],
706				'allowed_types' => $this->allowedTypesStr,
707				'operators' => $this->operators
708			],
709			'mad' => [
710				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
711				'description' => _('mad() - Median absolute deviation'),
712				'params' => $this->param1SecCount,
713				'allowed_types' => $this->allowedTypesNumeric,
714				'operators' => $this->operators
715			],
716			'max' => [
717				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE, ZBX_FUNCTION_TYPE_MATH],
718				'description' => _('max() - Maximum value for period T'),
719				'params' => $this->param1SecCount,
720				'allowed_types' => $this->allowedTypesNumeric,
721				'operators' => $this->operators
722			],
723			'mid' => [
724				'types' => [ZBX_FUNCTION_TYPE_STRING],
725				'description' => _('mid() - Returns a substring beginning at the character position specified by start for N characters'),
726				'params' => $this->param1SecCount + [
727					'start' => [
728						'C' => _('Start'),
729						'T' => T_ZBX_STR,
730						'A' => true
731					],
732					'length' => [
733						'C' => _('Length'),
734						'T' => T_ZBX_STR,
735						'A' => true
736					]
737				],
738				'allowed_types' => $this->allowedTypesStr,
739				'operators' => $this->operators
740			],
741			'min' => [
742				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE, ZBX_FUNCTION_TYPE_MATH],
743				'description' => _('min() - Minimum value for period T'),
744				'params' => $this->param1SecCount,
745				'allowed_types' => $this->allowedTypesNumeric,
746				'operators' => $this->operators
747			],
748			'mod' => [
749				'types' => [ZBX_FUNCTION_TYPE_MATH],
750				'description' => _('mod() - Division remainder'),
751				'params' => $this->param1SecCount + [
752					'denominator' => [
753						'C' => _('Division denominator'),
754						'T' => T_ZBX_STR,
755						'A' => true
756					]
757				],
758				'allowed_types' => $this->allowedTypesNumeric,
759				'operators' => $this->operators
760			],
761			'nodata' => [
762				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
763				'description' => _('nodata() - No data received during period of time T (1 - true, 0 - false), Mode (strict - ignore proxy time delay in sending data)'),
764				'params' => $this->param2SecMode,
765				'allowed_types' => $this->allowedTypesAny,
766				'operators' => ['=', '<>']
767			],
768			'now' => [
769				'types' => [ZBX_FUNCTION_TYPE_DATE_TIME],
770				'description' => _('now() - Number of seconds since the Epoch'),
771				'allowed_types' => $this->allowedTypesAny,
772				'operators' => $this->operators
773			],
774			'percentile' => [
775				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
776				'description' => _('percentile() - Percentile P of a period T'),
777				'params' => $this->param3SecPercent,
778				'allowed_types' => $this->allowedTypesNumeric,
779				'operators' => $this->operators
780			],
781			'pi' => [
782				'types' => [ZBX_FUNCTION_TYPE_MATH],
783				'description' => _('pi() - Returns the Pi constant'),
784				'allowed_types' => $this->allowedTypesAny
785			],
786			'power' => [
787				'types' => [ZBX_FUNCTION_TYPE_MATH],
788				'description' => _('power() - The power of a base value to a power value'),
789				'params' => $this->param1SecCount + [
790					'power' => [
791						'C' => _('Power value'),
792						'T' => T_ZBX_STR,
793						'A' => true
794					]
795				],
796				'allowed_types' => $this->allowedTypesNumeric,
797				'operators' => $this->operators
798			],
799			'radians' => [
800				'types' => [ZBX_FUNCTION_TYPE_MATH],
801				'description' => _('radians() - Converts a value from degrees to radians'),
802				'params' => $this->param1SecCount,
803				'allowed_types' => $this->allowedTypesNumeric,
804				'operators' => $this->operators
805			],
806			'rand' => [
807				'types' => [ZBX_FUNCTION_TYPE_MATH],
808				'description' => _('rand() - A random integer value'),
809				'allowed_types' => $this->allowedTypesAny
810			],
811			'repeat' => [
812				'types' => [ZBX_FUNCTION_TYPE_STRING],
813				'description' => _('repeat() - Returns a string composed of value repeated count times'),
814				'params' => $this->param1SecCount + [
815					'count' => [
816						'C' => _('Count'),
817						'T' => T_ZBX_STR,
818						'A' => true
819					]
820				],
821				'allowed_types' => $this->allowedTypesStr,
822				'operators' => $this->operators
823			],
824			'replace' => [
825				'types' => [ZBX_FUNCTION_TYPE_STRING],
826				'description' => _('replace() - Search value for occurrences of pattern, and replace with replacement'),
827				'params' => $this->param1SecCount + [
828					'pattern' => [
829						'C' => _('Pattern'),
830						'T' => T_ZBX_STR,
831						'A' => true
832					],
833					'replace' => [
834						'C' => _('Replacement'),
835						'T' => T_ZBX_STR,
836						'A' => true
837					]
838				],
839				'allowed_types' => $this->allowedTypesStr,
840				'operators' => $this->operators
841			],
842			'right' => [
843				'types' => [ZBX_FUNCTION_TYPE_STRING],
844				'description' => _('right() - Returns the rightmost count characters'),
845				'params' => $this->param1SecCount + [
846					'count' => [
847						'C' => _('Count'),
848						'T' => T_ZBX_STR,
849						'A' => true
850					]
851				],
852				'allowed_types' => $this->allowedTypesStr,
853				'operators' => $this->operators
854			],
855			'round' => [
856				'types' => [ZBX_FUNCTION_TYPE_MATH],
857				'description' => _('round() - Rounds a value to decimal places'),
858				'params' => $this->param1SecCount + [
859					'decimals' => [
860						'C' => _('Decimal places'),
861						'T' => T_ZBX_STR,
862						'A' => true
863					]
864				],
865				'allowed_types' => $this->allowedTypesNumeric,
866				'operators' => $this->operators
867			],
868			'rtrim' => [
869				'types' => [ZBX_FUNCTION_TYPE_STRING],
870				'description' => _('rtrim() - Removes specified characters from the end of a string'),
871				'params' => $this->param1SecCount + [
872					'chars' => [
873						'C' => _('Chars'),
874						'T' => T_ZBX_STR,
875						'A' => false
876					]
877				],
878				'allowed_types' => $this->allowedTypesStr,
879				'operators' => $this->operators
880			],
881			'signum' => [
882				'types' => [ZBX_FUNCTION_TYPE_MATH],
883				'description' => _('signum() - Returns -1 if a value is negative, 0 if a value is zero, 1 if a value is positive'),
884				'params' => $this->param1SecCount,
885				'allowed_types' => $this->allowedTypesNumeric,
886				'operators' => $this->operators
887			],
888			'sin' => [
889				'types' => [ZBX_FUNCTION_TYPE_MATH],
890				'description' => _('sin() - The sine of a value, where the value is an angle expressed in radians'),
891				'params' => $this->param1SecCount,
892				'allowed_types' => $this->allowedTypesNumeric,
893				'operators' => $this->operators
894			],
895			'sinh' => [
896				'types' => [ZBX_FUNCTION_TYPE_MATH],
897				'description' => _('sinh() - The hyperbolic sine of a value'),
898				'params' => $this->param1SecCount,
899				'allowed_types' => $this->allowedTypesNumeric,
900				'operators' => $this->operators
901			],
902			'skewness' => [
903				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
904				'description' => _('skewness() - Measures the asymmetry of the probability distribution'),
905				'params' => $this->param1SecCount,
906				'allowed_types' => $this->allowedTypesNumeric,
907				'operators' => $this->operators
908			],
909			'sqrt' => [
910				'types' => [ZBX_FUNCTION_TYPE_MATH],
911				'description' => _('sqrt() - Square root of a value'),
912				'params' => $this->param1SecCount,
913				'allowed_types' => $this->allowedTypesNumeric,
914				'operators' => $this->operators
915			],
916			'stddevpop' => [
917				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
918				'description' => _('stddevpop() - Population standard deviation'),
919				'params' => $this->param1SecCount,
920				'allowed_types' => $this->allowedTypesNumeric,
921				'operators' => $this->operators
922			],
923			'stddevsamp' => [
924				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
925				'description' => _('stddevsamp() - Sample standard deviation'),
926				'params' => $this->param1SecCount,
927				'allowed_types' => $this->allowedTypesNumeric,
928				'operators' => $this->operators
929			],
930			'sum' => [
931				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE, ZBX_FUNCTION_TYPE_MATH],
932				'description' => _('sum() - Sum of values of a period T'),
933				'params' => $this->param1SecCount,
934				'allowed_types' => $this->allowedTypesNumeric,
935				'operators' => $this->operators
936			],
937			'sumofsquares' => [
938				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
939				'description' => _('sumofsquares() - The sum of squares'),
940				'params' => $this->param1SecCount,
941				'allowed_types' => $this->allowedTypesNumeric,
942				'operators' => $this->operators
943			],
944			'tan' => [
945				'types' => [ZBX_FUNCTION_TYPE_MATH],
946				'description' => _('tan() - The tangent of a value'),
947				'params' => $this->param1SecCount,
948				'allowed_types' => $this->allowedTypesNumeric,
949				'operators' => $this->operators
950			],
951			'time' => [
952				'types' => [ZBX_FUNCTION_TYPE_DATE_TIME],
953				'description' => _('time() - Current time'),
954				'allowed_types' => $this->allowedTypesAny,
955				'operators' => $this->operators
956			],
957			'timeleft' => [
958				'types' => [ZBX_FUNCTION_TYPE_PREDICTION],
959				'description' => _('timeleft() - Time to reach threshold estimated based on period T'),
960				'params' => $this->paramTimeleft,
961				'allowed_types' => $this->allowedTypesNumeric,
962				'operators' => $this->operators
963			],
964			'trendavg' => [
965				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
966				'description' => _('trendavg() - Average value of a period T with exact period shift'),
967				'params' => $this->param1Period,
968				'allowed_types' => $this->allowedTypesNumeric,
969				'operators' => $this->operators
970			],
971			'trendcount' => [
972				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
973				'description' => _('trendcount() - Number of successfully retrieved values for period T'),
974				'params' => $this->param1Period,
975				'allowed_types' => $this->allowedTypesAny,
976				'operators' => $this->operators
977			],
978			'trendmax' => [
979				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
980				'description' => _('trendmax() - Maximum value for period T with exact period shift'),
981				'params' => $this->param1Period,
982				'allowed_types' => $this->allowedTypesNumeric,
983				'operators' => $this->operators
984			],
985			'trendmin' => [
986				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
987				'description' => _('trendmin() - Minimum value for period T with exact period shift'),
988				'params' => $this->param1Period,
989				'allowed_types' => $this->allowedTypesNumeric,
990				'operators' => $this->operators
991			],
992			'trendsum' => [
993				'types' => [ZBX_FUNCTION_TYPE_HISTORY],
994				'description' => _('trendsum() - Sum of values of a period T with exact period shift'),
995				'params' => $this->param1Period,
996				'allowed_types' => $this->allowedTypesNumeric,
997				'operators' => $this->operators
998			],
999			'trim' => [
1000				'types' => [ZBX_FUNCTION_TYPE_STRING],
1001				'description' => _('trim() - Remove specified characters from the beginning and the end of a string'),
1002				'params' => $this->param1SecCount + [
1003					'chars' => [
1004						'C' => _('Chars'),
1005						'T' => T_ZBX_STR,
1006						'A' => false
1007					]
1008				],
1009				'allowed_types' => $this->allowedTypesStr,
1010				'operators' => $this->operators
1011			],
1012			'truncate' => [
1013				'types' => [ZBX_FUNCTION_TYPE_MATH],
1014				'description' => _('truncate() - Truncates a value to decimal places'),
1015				'params' => $this->param1SecCount + [
1016					'decimals' => [
1017						'C' => _('Decimal places'),
1018						'T' => T_ZBX_STR,
1019						'A' => true
1020					]
1021				],
1022				'allowed_types' => $this->allowedTypesNumeric,
1023				'operators' => $this->operators
1024			],
1025			'varpop' => [
1026				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
1027				'description' => _('varpop() - Population variance'),
1028				'params' => $this->param1SecCount,
1029				'allowed_types' => $this->allowedTypesNumeric,
1030				'operators' => $this->operators
1031			],
1032			'varsamp' => [
1033				'types' => [ZBX_FUNCTION_TYPE_AGGREGATE],
1034				'description' => _('varsamp() - Sample variance'),
1035				'params' => $this->param1SecCount,
1036				'allowed_types' => $this->allowedTypesNumeric,
1037				'operators' => $this->operators
1038			]
1039		];
1040
1041		CArrayHelper::sort($this->functions, ['description']);
1042	}
1043
1044	protected function checkInput() {
1045		$fields = [
1046			'dstfrm' =>				'string|fatal',
1047			'dstfld1' =>			'string|not_empty',
1048			'expression' =>			'string',
1049			'itemid' =>				'db items.itemid',
1050			'parent_discoveryid' =>	'db items.itemid',
1051			'function' =>			'in '.implode(',', array_keys($this->functions)),
1052			'operator' =>			'in '.implode(',', $this->operators),
1053			'params' =>				'',
1054			'paramtype' =>			'in '.implode(',', [PARAM_TYPE_TIME, PARAM_TYPE_COUNTS]),
1055			'value' =>				'string|not_empty',
1056			'hostid' =>				'db hosts.hostid',
1057			'groupid' =>			'db hosts_groups.hostgroupid',
1058			'add' =>				'in 1'
1059		];
1060
1061		$ret = $this->validateInput($fields);
1062
1063		if (!$ret) {
1064			$output = [];
1065			if (($messages = getMessages()) !== null) {
1066				$output['errors'] = $messages->toString();
1067			}
1068
1069			if ($this->hasInput('add')) {
1070				$this->setResponse(
1071					(new CControllerResponseData(['main_block' => json_encode($output)]))->disableView()
1072				);
1073			}
1074			else {
1075				$ret = true;
1076			}
1077		}
1078
1079		return $ret;
1080	}
1081
1082	protected function checkPermissions() {
1083		return true;
1084	}
1085
1086	protected function doAction() {
1087		$expression_parser = new CExpressionParser(['usermacros' => true, 'lldmacros' => true]);
1088		$expression_validator = new CExpressionValidator([
1089			'usermacros' => true,
1090			'lldmacros' => true,
1091			'partial' => true
1092		]);
1093
1094		$itemid = $this->getInput('itemid', 0);
1095		$function = $this->getInput('function', 'last');
1096		$operator = $this->getInput('operator', '=');
1097		$param_type = $this->getInput('paramtype', PARAM_TYPE_TIME);
1098		$dstfld1 = $this->getInput('dstfld1');
1099		$expression = $this->getInput('expression', '');
1100		$params = $this->getInput('params', []);
1101		$value = $this->getInput('value', 0);
1102
1103		$item = false;
1104
1105		// Opening the popup when editing an expression in the trigger constructor.
1106		if (($dstfld1 === 'expr_temp' || $dstfld1 === 'recovery_expr_temp') && $expression !== '') {
1107			$expression = utf8RawUrlDecode($expression);
1108
1109			if ($expression_parser->parse($expression) == CParser::PARSE_SUCCESS) {
1110				$math_function_token = null;
1111				$hist_function_token = null;
1112				$function_token_index = null;
1113				$tokens = $expression_parser->getResult()->getTokens();
1114
1115				foreach ($tokens as $index => $token) {
1116					switch ($token['type']) {
1117						case CExpressionParserResult::TOKEN_TYPE_MATH_FUNCTION:
1118							$math_function_token = $token;
1119							$function_token_index = $index;
1120
1121							foreach ($token['data']['parameters'] as $parameter) {
1122								foreach ($parameter['data']['tokens'] as $parameter_token) {
1123									if ($parameter_token['type'] == CExpressionParserResult::TOKEN_TYPE_HIST_FUNCTION) {
1124										$hist_function_token = $parameter_token;
1125										break 2;
1126									}
1127								}
1128							}
1129							break 2;
1130
1131						case CExpressionParserResult::TOKEN_TYPE_HIST_FUNCTION:
1132							$hist_function_token = $token;
1133							$function_token_index = $index;
1134							break 2;
1135					}
1136				}
1137
1138				if ($function_token_index !== null) {
1139					/*
1140					 * Try to find an operator and a value.
1141					 * The value and operator can be extracted only if they immediately follow the function.
1142					 */
1143					$index = $function_token_index + 1;
1144
1145					if (array_key_exists($index, $tokens)
1146							&& $tokens[$index]['type'] == CExpressionParserResult::TOKEN_TYPE_OPERATOR
1147							&& in_array($tokens[$index]['match'], $this->operators)) {
1148						$operator = $tokens[$index]['match'];
1149						$index++;
1150
1151						if (array_key_exists($index, $tokens)) {
1152							if ($tokens[$index]['type'] == CExpressionParserResult::TOKEN_TYPE_NUMBER
1153									|| $tokens[$index]['type'] == CExpressionParserResult::TOKEN_TYPE_MACRO
1154									|| $tokens[$index]['type'] == CExpressionParserResult::TOKEN_TYPE_USER_MACRO
1155									|| $tokens[$index]['type'] == CExpressionParserResult::TOKEN_TYPE_LLD_MACRO) {
1156								$value = $tokens[$index]['match'];
1157							}
1158							elseif ($tokens[$index]['type'] == CExpressionParserResult::TOKEN_TYPE_STRING) {
1159								$value = CExpressionParser::unquoteString($tokens[$index]['match']);
1160							}
1161							elseif ($tokens[$index]['type'] == CExpressionParserResult::TOKEN_TYPE_OPERATOR
1162									&& array_key_exists($index + 1, $tokens)
1163									&& $tokens[$index + 1]['type'] == CExpressionParserResult::TOKEN_TYPE_NUMBER) {
1164								$value = '-'.$tokens[$index + 1]['match'];
1165							}
1166						}
1167					}
1168
1169					// Get function parameters.
1170					$parameters = null;
1171
1172					if ($math_function_token) {
1173						$function = $math_function_token['data']['function'];
1174
1175						if ($hist_function_token && $hist_function_token['data']['function'] === 'last') {
1176							$parameters = $hist_function_token['data']['parameters'];
1177						}
1178					}
1179					else {
1180						$function = $hist_function_token['data']['function'];
1181						$parameters = $hist_function_token['data']['parameters'];
1182					}
1183
1184					if ($parameters !== null) {
1185						$host = $hist_function_token['data']['parameters'][0]['data']['host'];
1186						$key = $hist_function_token['data']['parameters'][0]['data']['item'];
1187
1188						$items = API::Item()->get([
1189							'output' => ['itemid', 'hostid', 'name', 'key_', 'value_type'],
1190							'selectHosts' => ['name'],
1191							'webitems' => true,
1192							'filter' => [
1193								'host' => $host,
1194								'key_' => $key
1195							]
1196						]);
1197
1198						if (!$items) {
1199							$items = API::ItemPrototype()->get([
1200								'output' => ['itemid', 'hostid', 'name', 'key_', 'value_type'],
1201								'selectHosts' => ['name'],
1202								'filter' => [
1203									'host' => $host,
1204									'key_' => $key
1205								]
1206							]);
1207						}
1208
1209						if (($item = reset($items)) === false) {
1210							error(_('Unknown host item, no such item in selected host'));
1211						}
1212					}
1213
1214					$params = [];
1215
1216					if ($parameters !== null && array_key_exists(1, $parameters)) {
1217						if ($function === "nodata" || $function === "fuzzytime") {
1218							$params[] = ($parameters[1]['type'] == CHistFunctionParser::PARAM_TYPE_QUOTED)
1219								? CHistFunctionParser::unquoteParam($parameters[1]['match'])
1220								: $parameters[1]['match'];
1221						}
1222						else {
1223							if ($parameters[1]['type'] == CHistFunctionParser::PARAM_TYPE_PERIOD) {
1224								$sec_num = $parameters[1]['data']['sec_num'];
1225								if ($sec_num !== '' && $sec_num[0] === '#') {
1226									$params[] = substr($sec_num, 1);
1227									$param_type = PARAM_TYPE_COUNTS;
1228								}
1229								else {
1230									$params[] = $sec_num;
1231									$param_type = PARAM_TYPE_TIME;
1232								}
1233								$params[] = $parameters[1]['data']['time_shift'];
1234							}
1235							else {
1236								$params[] = '';
1237								$params[] = '';
1238							}
1239						}
1240
1241						for ($i = 2; $i < count($parameters); $i++) {
1242							$parameter = $parameters[$i];
1243							$params[] = $parameter['type'] == CHistFunctionParser::PARAM_TYPE_QUOTED
1244								? CHistFunctionParser::unquoteParam($parameter['match'])
1245								: $parameter['match'];
1246						}
1247					}
1248				}
1249			}
1250		}
1251		// Opening an empty form or switching a function.
1252		else {
1253			$item = API::Item()->get([
1254				'output' => ['itemid', 'hostid', 'name', 'key_', 'value_type'],
1255				'selectHosts' => ['host', 'name'],
1256				'itemids' => $itemid,
1257				'webitems' => true,
1258				'filter' => ['flags' => null]
1259			]);
1260
1261			$item = reset($item);
1262		}
1263
1264		if ($item) {
1265			$items = CMacrosResolverHelper::resolveItemNames([$item]);
1266			$item = $items[0];
1267
1268			$itemid = $item['itemid'];
1269			$item_value_type = $item['value_type'];
1270			$item_key = $item['key_'];
1271			$item_host_data = reset($item['hosts']);
1272			$description = $item_host_data['name'].NAME_DELIMITER.$item['name_expanded'];
1273		}
1274		else {
1275			$item_key = '';
1276			$description = '';
1277			$item_value_type = null;
1278		}
1279
1280		if ($param_type === null && array_key_exists($function, $this->functions)
1281				&& array_key_exists('params', $this->functions[$function])
1282				&& array_key_exists('M', $this->functions[$function]['params'])) {
1283			$param_type = is_array($this->functions[$function]['params']['M'])
1284				? reset($this->functions[$function]['params']['M'])
1285				: $this->functions[$function]['params']['M'];
1286		}
1287		elseif ($param_type === null) {
1288			$param_type = PARAM_TYPE_TIME;
1289		}
1290
1291		$data = [
1292			'parent_discoveryid' => $this->getInput('parent_discoveryid', ''),
1293			'dstfrm' => $this->getInput('dstfrm'),
1294			'dstfld1' => $dstfld1,
1295			'itemid' => $itemid,
1296			'value' => $value,
1297			'params' => $params,
1298			'paramtype' => $param_type,
1299			'item_description' => $description,
1300			'item_required' => !in_array($function, array_merge(getStandaloneFunctions(), getFunctionsConstants())),
1301			'functions' => $this->functions,
1302			'function' => $function,
1303			'function_type' => reset($this->functions[$function]['types']),
1304			'operator' => $operator,
1305			'item_key' => $item_key,
1306			'itemValueType' => $item_value_type,
1307			'selectedFunction' => null,
1308			'groupid' => $this->getInput('groupid', 0),
1309			'hostid' => $this->getInput('hostid', 0)
1310		];
1311
1312		// Check if submitted function is usable with selected item.
1313		foreach ($data['functions'] as $id => $f) {
1314			if (($data['itemValueType'] === null || array_key_exists($item_value_type, $f['allowed_types']))
1315					&& $id === $function) {
1316				$data['selectedFunction'] = $id;
1317				break;
1318			}
1319		}
1320
1321		if ($data['selectedFunction'] === null) {
1322			$data['selectedFunction'] = 'last';
1323			$data['function'] = 'last';
1324			$data['function_type'] = ZBX_FUNCTION_TYPE_HISTORY;
1325		}
1326
1327		// Remove functions that not correspond to chosen item.
1328		foreach ($data['functions'] as $id => $f) {
1329			if ($data['itemValueType'] !== null && !array_key_exists($data['itemValueType'], $f['allowed_types'])) {
1330				unset($data['functions'][$id]);
1331
1332				// Take first available function from list.
1333				if ($id === $data['function']) {
1334					$data['function'] = key($data['functions']);
1335					$data['function_type'] = reset($data['functions'][$data['function']]['types']);
1336					$data['operator'] = reset($data['functions'][$data['function']]['operators']);
1337				}
1338			}
1339		}
1340
1341		// Create and validate trigger expression before inserting it into textarea field.
1342		if ($this->getInput('add', false)) {
1343			try {
1344				if (in_array($function, getFunctionsConstants())) {
1345					$data['expression'] = sprintf('%s()', $function);
1346				}
1347				elseif (in_array($function, getStandaloneFunctions())) {
1348					$data['expression'] = sprintf('%s()%s%s', $function, $operator,
1349						CExpressionParser::quoteString($data['value'])
1350					);
1351				}
1352				elseif ($data['item_description']) {
1353					// Quote function string parameters.
1354					foreach ($data['params'] as $param_key => $param) {
1355						if (!in_array($param_key, ['v', 'o', 'chars', 'fit', 'mode', 'pattern', 'replace', 'string'])
1356								|| !array_key_exists($param_key, $data['params'])
1357								|| $data['params'][$param_key] === '') {
1358							continue;
1359						}
1360
1361						$data['params'][$param_key] = quoteFunctionParam($param, true);
1362					}
1363
1364					// Combine sec|#num and <time_shift|period_shift> parameters into one.
1365					if (array_key_exists('last', $data['params'])) {
1366						if ($data['paramtype'] == PARAM_TYPE_COUNTS && zbx_is_int($data['params']['last'])) {
1367							$data['params']['last'] = '#'.$data['params']['last'];
1368						}
1369					}
1370					else {
1371						$data['params']['last'] = '';
1372					}
1373
1374					if (array_key_exists('shift', $data['params']) && $data['params']['shift'] !== '') {
1375						$data['params']['last'] .= ':'.$data['params']['shift'];
1376					}
1377					elseif (array_key_exists('period_shift', $data['params'])
1378							&& $data['params']['period_shift'] !== '') {
1379						$data['params']['last'] .= ':'.$data['params']['period_shift'];
1380					}
1381					unset($data['params']['shift'], $data['params']['period_shift']);
1382
1383					// Functions where item is wrapped in last() like func(last(/host/item)).
1384					$last_functions = [
1385						'abs', 'acos', 'ascii', 'asin', 'atan', 'atan2', 'between', 'bitand', 'bitlength', 'bitlshift',
1386						'bitnot', 'bitor', 'bitrshift', 'bitxor', 'bytelength', 'cbrt', 'ceil', 'char', 'concat', 'cos',
1387						'cosh', 'cot', 'degrees', 'exp', 'expm1', 'floor', 'in', 'insert', 'left', 'log', 'log10',
1388						'ltrim', 'mid', 'mod', 'power', 'radians', 'repeat', 'replace', 'right', 'round', 'signum',
1389						'sin', 'sinh', 'sqrt', 'tan', 'trim', 'truncate'
1390					];
1391
1392					if (in_array($function, $last_functions)) {
1393						$last_params = $data['params']['last'];
1394						unset($data['params']['last']);
1395						$fn_params = rtrim(implode(',', $data['params']), ',');
1396
1397						$data['expression'] = sprintf('%s(last(/%s/%s%s)%s)%s%s',
1398							$function,
1399							$item_host_data['host'],
1400							$data['item_key'],
1401							($last_params === '') ? '' : ','.$last_params,
1402							($fn_params === '') ? '' : ','.$fn_params,
1403							$operator,
1404							CExpressionParser::quoteString($data['value'])
1405						);
1406					}
1407					else {
1408						$fn_params = rtrim(implode(',', $data['params']), ',');
1409
1410						$data['expression'] = sprintf('%s(/%s/%s%s)%s%s',
1411							$function,
1412							$item_host_data['host'],
1413							$data['item_key'],
1414							($fn_params === '') ? '' : ','.$fn_params,
1415							$operator,
1416							CExpressionParser::quoteString($data['value'])
1417						);
1418					}
1419				}
1420				else {
1421					error(_('Item not selected'));
1422				}
1423
1424				if (array_key_exists('expression', $data)) {
1425					// Parse and validate trigger expression.
1426					if ($expression_parser->parse($data['expression']) == CParser::PARSE_SUCCESS) {
1427						if (!$expression_validator->validate($expression_parser->getResult()->getTokens())) {
1428							error(_s('Invalid condition: %1$s.', $expression_validator->getError()));
1429						}
1430					}
1431					else {
1432						error($expression_parser->getError());
1433					}
1434				}
1435			}
1436			catch (Exception $e) {
1437				error($e->getMessage());
1438				error(_('Cannot insert trigger expression'));
1439			}
1440
1441			if (($messages = getMessages()) !== null) {
1442				$output = [
1443					'errors' => $messages->toString()
1444				];
1445			}
1446			else {
1447				$output = [
1448					'expression' => $data['expression'],
1449					'dstfld1' => $data['dstfld1'],
1450					'dstfrm' => $data['dstfrm']
1451				];
1452			}
1453
1454			$this->setResponse(
1455				(new CControllerResponseData(['main_block' => json_encode($output)]))->disableView()
1456			);
1457		}
1458		else {
1459			$this->setResponse(new CControllerResponseData(
1460				$data + [
1461					'title' => _('Condition'),
1462					'errors' => hasErrorMesssages() ? getMessages() : null,
1463					'user' => [
1464						'debug_mode' => $this->getDebugMode()
1465					]
1466				]
1467			));
1468		}
1469	}
1470}
1471