Completed
Branch master (1f9106)
by Nils
02:44
created

Scanner::scan()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 29
rs 8.439
cc 5
eloc 16
nc 4
nop 0
1
<?php
2
3
namespace whm\Smoke\Scanner;
4
5
use Ivory\HttpAdapter\HttpAdapterInterface;
6
use phmLabs\Components\Annovent\Dispatcher;
7
use phmLabs\Components\Annovent\Event\Event;
8
use whm\Smoke\Extensions\SmokeResponseRetriever\Retriever\Retriever;
9
use whm\Smoke\Http\Response;
10
use whm\Smoke\Rules\ValidationFailedException;
11
12
class Scanner
13
{
14
    const ERROR = 'error';
15
    const PASSED = 'passed';
16
17
    private $rules;
18
    private $eventDispatcher;
19
20
    private $responseRetriever;
21
22
    private $status = 0;
23
24
    public function __construct(array $rules, HttpAdapterInterface $client, Dispatcher $eventDispatcher, Retriever $responseRetriever)
25
    {
26
        $eventDispatcher->simpleNotify('Scanner.Init', array('rules' => $rules, 'httpClient' => $client, 'dispatcher' => $eventDispatcher));
27
28
        $this->rules = $rules;
29
        $this->eventDispatcher = $eventDispatcher;
30
31
        $this->responseRetriever = $responseRetriever;
32
33
        $this->eventDispatcher->simpleNotify('Scanner.Init.ResponseRetriever', array('responseRetriever' => $this->responseRetriever));
34
    }
35
36
    public function scan()
37
    {
38
        $this->eventDispatcher->simpleNotify('Scanner.Scan.Begin');
39
40
        while (($response = $this->responseRetriever->next()) && !$this->eventDispatcher->notifyUntil(new Event('Scanner.Scan.isStopped'))) {
41
42
            // this is the url filter
43
            if ($this->eventDispatcher->notifyUntil(new Event('Scanner.ProcessHtml.isFiltered', array('uri' => $response->getUri())))) {
44
                continue;
45
            }
46
47
            $resultArray = $this->checkResponse($response);
48
49
            $result = new Result($response->getUri(),
50
                $resultArray['type'],
51
                $response,
52
                '',
53
                $resultArray['time']);
54
55
            if ($result->isFailure()) {
56
                $result->setMessages($resultArray['messages']);
57
                $this->status = 1;
58
            }
59
60
            $this->eventDispatcher->simpleNotify('Scanner.Scan.Validate', array('result' => $result));
61
        }
62
63
        $this->eventDispatcher->simpleNotify('Scanner.Scan.Finish');
64
    }
65
66
    public function getStatus()
67
    {
68
        return $this->status;
69
    }
70
71
    private function checkResponse(Response $response)
72
    {
73
        $messages = [];
74
75
        $startTime = microtime(true);
76
        foreach ($this->rules as $name => $rule) {
77
            if ($this->eventDispatcher->notifyUntil(new Event('Scanner.CheckResponse.isFiltered', array('ruleName' => $name, 'rule' => $rule, 'response' => $response)))) {
78
                continue;
79
            }
80
            try {
81
                $rule->validate($response);
82
            } catch (ValidationFailedException $e) {
83
                $messages[$name] = $e->getMessage();
84
            }
85
        }
86
        $endTime = microtime(true);
87
88
        // calculate time in seconds
89
        $time = round(($endTime - $startTime) * 1000, 5);
90
91
        if (count($messages) > 0) {
92
            $resultArray = ['messages' => $messages, 'time' => $time, 'type' => self::ERROR];
93
        } else {
94
            $resultArray = ['messages' => [], 'time' => $time, 'type' => self::PASSED];
95
        }
96
97
        return $resultArray;
98
    }
99
}
100