Detector::fetch()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 11
nc 2
nop 1
1
<?php
2
/**
3
 * This file is part of SHIELDFY Web Application Firewall Detector.
4
 * (c) 2016 SHIELDFY, All rights reserved.
5
 *
6
 * The code provided was developed by Matthias "Nihylum" Kaschubowski
7
 *
8
 * The applied license is stored at the root directory of this package.
9
 */
10
namespace Shieldfy;
11
12
use Shieldfy\Exception\InvalidUrlException;
13
14
/**
15
 * Detector Class.
16
 *
17
 * @package shieldfy.waf-detector
18
 *
19
 * @author  Matthias Kaschubowski <[email protected]>
20
 */
21
class Detector
22
{
23
    /**
24
     * Holds all firewall identification interfaces.
25
     *
26
     * @var FirewallInterface[]
27
     */
28
    protected $firewalls = [];
29
30
    /**
31
     * holds the general cURL settings.
32
     *
33
     * @var array
34
     */
35
    protected $cUrlOptions = [
36
        CURLOPT_HEADER         => 1,
37
        CURLOPT_VERBOSE        => 0,
38
        CURLOPT_RETURNTRANSFER => 1,
39
        CURLOPT_USERAGENT      => 'Mozilla/5.0 (Windows; U;Windows NT 5.1; ru; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9',
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
40
        CURLOPT_FOLLOWLOCATION => 1,
41
        CURLOPT_SSL_VERIFYPEER => 0,
42
        CURLOPT_SSL_VERIFYHOST => 0,
43
    ];
44
45
    /**
46
     * Detector constructor.
47
     *
48
     * @param FirewallInterface[] ...$firewalls
49
     */
0 ignored issues
show
Documentation introduced by
Should the type for parameter $firewalls not be FirewallInterface[][]?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
50
    public function __construct(FirewallInterface ...$firewalls)
51
    {
52
        $this->firewalls = $firewalls;
0 ignored issues
show
Documentation Bug introduced by
It seems like $firewalls of type array<integer,array<inte...fy\FirewallInterface>>> is incompatible with the declared type array<integer,object<Shieldfy\FirewallInterface>> of property $firewalls.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
53
    }
54
55
    /**
56
     * creates a report (iterator) of the provided url.
57
     *
58
     * The iterator provides a firewall name as it keys and a checkup-result boolean as it values.
59
     *
60
     * @param string $url
61
     *
62
     * @return \Iterator
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use \Generator.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
63
     */
64
    public function detect($url)
65
    {
66
        if (false === filter_var($url, FILTER_VALIDATE_URL)) {
67
            throw new InvalidUrlException("incompatible url given: {$url}");
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $url instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
68
        }
69
70
        $response = $this->fetch($url);
71
72
        foreach ($this->firewalls as $firewall) {
73
            yield $firewall->getName() => $firewall->detect($response['headers'], $response['body'], $url);
74
        }
75
    }
76
77
    /**
78
     * fetches the contents of the given url.
79
     *
80
     * @param string $url
81
     *
82
     * @return array [headers=>..., body=>...]
83
     */
84
    protected function fetch($url)
85
    {
86
        $resource = curl_init($url);
87
        curl_setopt_array($resource, $this->cUrlOptions);
88
        $response = curl_exec($resource);
89
90
        if (! in_array($httpCode = curl_getinfo($resource, CURLINFO_HTTP_CODE), [302, 301, 304, 200])) {
91
            throw new InvalidUrlException("Given url returns abnormal http status code: {$httpCode}");
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $httpCode instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
92
        }
93
94
        curl_close($resource);
95
96
        list($headerString, $bodyString) = explode("\r\n\r\n", $response, 2);
97
98
        return [
99
            'headers' => iterator_to_array($this->marshalHeaders($headerString)),
100
            'body'    => $bodyString,
101
        ];
102
    }
103
104
    /**
105
     * marshals the header from a header string.
106
     *
107
     * @param $headerString
108
     *
109
     * @return \Generator
110
     */
111
    protected function marshalHeaders($headerString)
112
    {
113
        $headers = explode("\r\n", $headerString);
114
115
        foreach ($headers as $current) {
116
            if (false !== strpos($current, ': ')) {
117
                list($key, $value) = explode(': ', $current, 2);
118
                yield strtolower($key) => $value;
119
            }
120
        }
121
    }
122
}
123