1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
<?php
/* Icinga Web 2 - EventDB | (c) 2017 Icinga Development Team | GPLv2+ */
namespace Icinga\Module\Eventdb\Data;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterAnd;
use Icinga\Data\Filter\FilterOr;
use Icinga\Exception\InvalidPropertyException;
/**
* Class LegacyFilterParser
*
* Utility class to parse Icinga-web 1.x JSON filters of the EventDB module
*/
class LegacyFilterParser
{
/**
* @param $json string JSON data
* @param $host string Icinga host name (for default host filter and logging)
* @param $service string Icinga service name (for logging)
*
* @return Filter
* @throws InvalidPropertyException When filter could not be parsed
*/
static public function parse($json, $host, $service = null)
{
$json = static::fixJSONQuotes($json);
$data = json_decode($json, false, 5);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new InvalidPropertyException(
'Could not decode legacy filter (host=%s)%s (%s): %s',
$host,
($service ? ' (service=' . $service . ')' : ''),
json_last_error_msg(),
$json
);
}
$filter = new FilterAnd();
if (property_exists($data, 'host')) {
// Note: we can' support regexp right now, but we replace '.*' to a normal wildcard
$data->host = str_replace('.*', '*', $data->host);
if ($data->host === '*') {
$data->host = null;
}
} else {
$data->host = $host;
}
if ($data->host !== null) {
$filter->andFilter(Filter::expression('host_name', '=', $data->host));
}
static::handleArray($filter, $data, 'programInclusion', 'program');
static::handleArray($filter, $data, 'programExclusion', 'program', '!=');
static::handleArray($filter, $data, 'priorityExclusion', 'priority', '!=');
static::handleArray($filter, $data, 'sourceExclusion', 'source', '!=');
static::handleArray($filter, $data, 'facilityExclusion', 'facility', '!=');
// TODO: msg - when really needed
// TODO: startTime - when really needed
// Note: any other field or data part gets ignored...
return $filter;
}
protected static function handleArray(Filter $filter, $data, $property, $filterAttr, $op = '=')
{
if (property_exists($data, $property) && ! empty($data->$property)) {
if ($op === '!=') {
$subFilter = $filter;
} else {
$subFilter = new FilterOr;
}
/*
if (is_array($data->$property) && count($data->$property) === 1) {
$data->$property = current($data->$property);
}
*/
if (! is_array($data->$property)) {
$data->$property = array($data->$property);
}
foreach ($data->$property as $val) {
$subFilter->addFilter(Filter::expression($filterAttr, $op, $val));
}
if ($subFilter !== $filter) {
$filters = $subFilter->filters();
if ($filter->isChain() && count($filters) > 1) {
$filter->andFilter($subFilter);
} else {
$filter->andFilter(current($filters));
}
}
}
}
/**
* @author partially by NikiC https://stackoverflow.com/users/385378/nikic
* @source partially from https://stackoverflow.com/a/20440596/449813
*
* @param $json string
*
* @return string
*/
public static function fixJSONQuotes($json)
{
// fix unquoted identifiers
$json = preg_replace('/([{,]+)(\s*)([^"]+?)\s*:/', '$1"$3":', $json);
$regex = <<<'REGEX'
~
"[^"\\]*(?:\\.|[^"\\]*)*"
(*SKIP)(*F)
| '([^'\\]*(?:\\.|[^'\\]*)*)'
~x
REGEX;
return preg_replace_callback($regex, function ($matches) {
return '"' . preg_replace('~\\\\.(*SKIP)(*F)|"~', '\\"', $matches[1]) . '"';
}, $json);
}
/**
* Basic check if it looks like a JSON filter
*
* @param $string
*
* @return bool
*/
static public function isJsonFilter($string)
{
if (! $string || ! is_string($string)) {
return false;
}
$string = trim($string);
if (empty($string)) {
return false;
}
if (preg_match('/^\{.*\}$/s', $string)) {
// looks like JSON data
return true;
}
return false;
}
}
|