You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
311 lines
6.5 KiB
311 lines
6.5 KiB
1 year ago
|
<?php
|
||
|
/*
|
||
|
** Zabbix
|
||
|
** Copyright (C) 2001-2023 Zabbix SIA
|
||
|
**
|
||
|
** This program is free software; you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation; either version 2 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program; if not, write to the Free Software
|
||
|
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
**/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Class is used to validate and parse a trigger function.
|
||
|
*/
|
||
|
class C10FunctionParser extends CParser {
|
||
|
|
||
|
const STATE_NEW = 0;
|
||
|
const STATE_END = 1;
|
||
|
const STATE_UNQUOTED = 2;
|
||
|
const STATE_QUOTED = 3;
|
||
|
const STATE_END_OF_PARAMS = 4;
|
||
|
|
||
|
const PARAM_ARRAY = 0;
|
||
|
const PARAM_UNQUOTED = 1;
|
||
|
const PARAM_QUOTED = 2;
|
||
|
|
||
|
private $function = '';
|
||
|
private $parameters = '';
|
||
|
private $params_raw = [];
|
||
|
|
||
|
/**
|
||
|
* Returns true if the char is allowed in the function name, false otherwise.
|
||
|
*
|
||
|
* @param string $c
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
protected function isFunctionChar($c) {
|
||
|
return ($c >= 'a' && $c <= 'z');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Parse a trigger function and parameters and put them into $this->params_raw array.
|
||
|
*
|
||
|
* @param string $source
|
||
|
* @param int $pos
|
||
|
*/
|
||
|
public function parse($source, $pos = 0) {
|
||
|
$this->length = 0;
|
||
|
$this->match = '';
|
||
|
$this->function = '';
|
||
|
$this->parameters = '';
|
||
|
$this->params_raw = [];
|
||
|
|
||
|
for ($p = $pos; isset($source[$p]) && $this->isFunctionChar($source[$p]); $p++) {
|
||
|
}
|
||
|
|
||
|
if ($p == $pos) {
|
||
|
return self::PARSE_FAIL;
|
||
|
}
|
||
|
|
||
|
$p2 = $p;
|
||
|
|
||
|
$params_raw = [
|
||
|
'type' => self::PARAM_ARRAY,
|
||
|
'raw' => '',
|
||
|
'pos' => $p - $pos,
|
||
|
'parameters' => []
|
||
|
];
|
||
|
if (!$this->parseFunctionParameters($source, $p, $params_raw['parameters'])) {
|
||
|
return self::PARSE_FAIL;
|
||
|
}
|
||
|
|
||
|
$params_raw['raw'] = substr($source, $p2, $p - $p2);
|
||
|
|
||
|
$this->length = $p - $pos;
|
||
|
$this->match = substr($source, $pos, $this->length);
|
||
|
$this->function = substr($source, $pos, $p2 - $pos);
|
||
|
$this->parameters = substr($source, $p2 + 1, $p - $p2 - 2);
|
||
|
$this->params_raw = $params_raw;
|
||
|
|
||
|
return isset($source[$p]) ? self::PARSE_SUCCESS_CONT : self::PARSE_SUCCESS;
|
||
|
}
|
||
|
|
||
|
private function parseFunctionParameters($source, &$pos, array &$parameters) {
|
||
|
if (!isset($source[$pos]) || $source[$pos] != '(') {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$_parameters = [];
|
||
|
$state = self::STATE_NEW;
|
||
|
$num = 0;
|
||
|
|
||
|
for ($p = $pos + 1; isset($source[$p]); $p++) {
|
||
|
switch ($state) {
|
||
|
// a new parameter started
|
||
|
case self::STATE_NEW:
|
||
|
switch ($source[$p]) {
|
||
|
case ' ':
|
||
|
break;
|
||
|
|
||
|
case ',':
|
||
|
$_parameters[$num++] = [
|
||
|
'type' => self::PARAM_UNQUOTED,
|
||
|
'raw' => '',
|
||
|
'pos' => $p - $pos
|
||
|
];
|
||
|
break;
|
||
|
|
||
|
case ')':
|
||
|
$_parameters[$num] = [
|
||
|
'type' => self::PARAM_UNQUOTED,
|
||
|
'raw' => '',
|
||
|
'pos' => $p - $pos
|
||
|
];
|
||
|
$state = self::STATE_END_OF_PARAMS;
|
||
|
break;
|
||
|
|
||
|
case '"':
|
||
|
$_parameters[$num] = [
|
||
|
'type' => self::PARAM_QUOTED,
|
||
|
'raw' => $source[$p],
|
||
|
'pos' => $p - $pos
|
||
|
];
|
||
|
$state = self::STATE_QUOTED;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
$_parameters[$num] = [
|
||
|
'type' => self::PARAM_UNQUOTED,
|
||
|
'raw' => $source[$p],
|
||
|
'pos' => $p - $pos
|
||
|
];
|
||
|
$state = self::STATE_UNQUOTED;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// end of parameter
|
||
|
case self::STATE_END:
|
||
|
switch ($source[$p]) {
|
||
|
case ' ':
|
||
|
break;
|
||
|
|
||
|
case ',':
|
||
|
$state = self::STATE_NEW;
|
||
|
$num++;
|
||
|
break;
|
||
|
|
||
|
case ')':
|
||
|
$state = self::STATE_END_OF_PARAMS;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break 3;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// an unquoted parameter
|
||
|
case self::STATE_UNQUOTED:
|
||
|
switch ($source[$p]) {
|
||
|
case ')':
|
||
|
$state = self::STATE_END_OF_PARAMS;
|
||
|
break;
|
||
|
|
||
|
case ',':
|
||
|
$state = self::STATE_NEW;
|
||
|
$num++;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
$_parameters[$num]['raw'] .= $source[$p];
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// a quoted parameter
|
||
|
case self::STATE_QUOTED:
|
||
|
$_parameters[$num]['raw'] .= $source[$p];
|
||
|
|
||
|
if ($source[$p] == '"' && $source[$p - 1] != '\\') {
|
||
|
$state = self::STATE_END;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// end of parameters
|
||
|
case self::STATE_END_OF_PARAMS:
|
||
|
break 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($state == self::STATE_END_OF_PARAMS) {
|
||
|
$parameters = $_parameters;
|
||
|
$pos = $p;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the left part of the trigger function without parameters.
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getFunction() {
|
||
|
return $this->function;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the parameters of the function.
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getParameters() {
|
||
|
return $this->parameters;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the list of the parameters.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getParamsRaw() {
|
||
|
return $this->params_raw;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the number of the parameters.
|
||
|
*
|
||
|
* @return int
|
||
|
*/
|
||
|
public function getParamsNum() {
|
||
|
return array_key_exists('parameters', $this->params_raw) ? count($this->params_raw['parameters']) : 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Unquotes special symbols in item the parameter
|
||
|
*
|
||
|
* @param string $param
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
private static function unquoteParam($param) {
|
||
|
$unquoted = '';
|
||
|
|
||
|
for ($p = 1; isset($param[$p]); $p++) {
|
||
|
if ($param[$p] == '\\' && $param[$p + 1] == '"') {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$unquoted .= $param[$p];
|
||
|
}
|
||
|
|
||
|
return substr($unquoted, 0, -1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns an unquoted parameter.
|
||
|
*
|
||
|
* @param int $n the number of the requested parameter
|
||
|
*
|
||
|
* @return string|null
|
||
|
*/
|
||
|
public function getParam($n) {
|
||
|
$num = 0;
|
||
|
|
||
|
foreach ($this->params_raw['parameters'] as $param) {
|
||
|
if ($num++ == $n) {
|
||
|
switch ($param['type']) {
|
||
|
case self::PARAM_UNQUOTED:
|
||
|
// return parameter without any changes
|
||
|
return $param['raw'];
|
||
|
case self::PARAM_QUOTED:
|
||
|
return $this->unquoteParam($param['raw']);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns unquoted parameters.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getParams(): array {
|
||
|
if (!array_key_exists('parameters', $this->params_raw)) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
$parameters = [];
|
||
|
|
||
|
foreach ($this->params_raw['parameters'] as $param) {
|
||
|
$parameters[] = $param['type'] == self::PARAM_QUOTED ? $this->unquoteParam($param['raw']) : $param['raw'];
|
||
|
}
|
||
|
|
||
|
return $parameters;
|
||
|
}
|
||
|
}
|