IDS   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 97
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 87.8%

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 0
dl 0
loc 97
ccs 36
cts 41
cp 0.878
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A fromFile() 0 14 4
A fromDefaults() 0 4 1
A __construct() 0 4 1
A analyzeData() 0 5 1
A getViolations() 0 4 1
C run() 0 35 14
1
<?php
2
3
namespace vakata\ids;
4
5
class IDS
6
{
7
    protected $rules;
8
    protected $violations;
9
10
    /**
11
     * Create an instance from a rule file. Rule files follow the Expose / PHPIDS format
12
     * @param  string   $path the path to the file to load
13
     * @return self         the new instance
14
     */
15 1
    public static function fromFile(string $path) : IDS
16
    {
17 1
        $rules = json_decode(file_get_contents($path), true);
18 1
        if (isset($rules['filters'])) {
19 1
            $rules = $rules['filters'];
20
        }
21 1
        $rules = array_map(function ($v) {
22 1
            if (isset($v['tags']) && isset($v['tags']['tag'])) {
23 1
                $v['tags'] = $v['tags']['tag'];
24
            }
25 1
            return $v;
26 1
        }, $rules);
27 1
        return new static($rules);
28
    }
29
    /**
30
     * Creates an instance from the default rule file that comes with the lib.
31
     * @return \vakata\ids\IDS       the new instance
32
     */
33 1
    public static function fromDefaults() : IDS
34
    {
35 1
        return static::fromFile(__DIR__ . '/filter_rules.json');
36
    }
37
    /**
38
     * Create an instance.
39
     * Each rule is and array and must contain `rule` and `impact` keys, and may contain `tags` and `description` keys
40
     * @param  array       $rules array or rule arrays
41
     */
42 2
    public function __construct(array $rules = [])
43
    {
44 2
        $this->rules = $rules;
45 2
    }
46
    /**
47
     * Analyze an array of data
48
     * @param  array        $data       the data to analyze
49
     * @param  int|null       $threshold if non-null analysis will stop once this impact number is reached
50
     * @param  array|null     $tags      if non-null only rules containing any of the supplied tags will be run
51
     * @return int                    the total impact of the data
52
     */
53 2
    public function analyzeData(array $data, int $threshold = null, array $tags = null) : int
54
    {
55 2
        $this->violations = [];
56 2
        return $this->run($data, $threshold, $tags);
57
    }
58
    /**
59
     * Get the violations from the last analyze call
60
     * @return array the violated rules and the values that violated them
61
     */
62
    public function getViolations() : array
63
    {
64
        return $this->violations;
65
    }
66 2
    protected function run(array $data, int $threshold = null, array $tags = null)
67
    {
68 2
        $impact = 0;
69 2
        foreach ($data as $v) {
70 2
            if (is_array($v)) {
71
                $impact += $this->run($v, $threshold !== null ? $threshold - $impact : null);
72
                if ($threshold !== null && $impact >= $threshold) {
73
                    return $impact;
74
                }
75
            } else {
76 2
                foreach ($this->rules as $rule) {
77 2
                    if ($tags !== null &&
78
                        (
79 1
                            !isset($rule['tags']) ||
80 1
                            !is_array($rule['tags']) ||
81 2
                            !count(array_intersect($tags, $rule['tags']))
82
                        )
83
                    ) {
84 1
                        continue;
85
                    }
86 2
                    if (preg_match('/' . $rule['rule'] . '/im', $v)) {
87 2
                        $impact += (int)$rule['impact'];
88 2
                        $this->violations[] = [
89 2
                            'rule' => $rule,
90 2
                            'value' => $v
91
                        ];
92 2
                        if ($threshold !== null && $impact >= $threshold) {
93 2
                            return $impact;
94
                        }
95
                    }
96
                }
97
            }
98
        }
99 2
        return $impact;
100
    }
101
}
102