Test Failed
Push — master ( 015f2b...92e6f8 )
by Antonio Carlos
02:56
created

Http::getConnectionTimeout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace PragmaRX\Health\Checkers;
4
5
use GuzzleHttp\Client as Guzzle;
6
use GuzzleHttp\TransferStats;
7
use Illuminate\Support\Collection;
8
use PragmaRX\Health\Support\Result;
9
10
class Http extends Base
11
{
12
    /**
13
     * @return Result
14
     */
15
    protected $secure = false;
16
17
    /**
18
     * @var
19
     */
20
    protected $guzzle;
21
22
    /**
23
     * @var
24
     */
25
    private $totalTime;
26
27
    /**
28
     * @var
29
     */
30
    private $url;
31
32
    /**
33
     * HTTP Checker.
34
     *
35
     * @return Result
36
     */
37 8
    public function check()
38
    {
39
        try {
40 8
            $health = [];
0 ignored issues
show
Unused Code introduced by
$health is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
41
42 8
            foreach ($this->getResourceUrlArray() as $url) {
43 8
                [$url, $parameters] = $this->parseConfigUrl($url);
0 ignored issues
show
Bug introduced by
The variable $parameters does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
44 8
45 8
                [$healthy, $message] = $this->checkWebPage(
0 ignored issues
show
Bug introduced by
The variable $healthy does not exist. Did you mean $health?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
Bug introduced by
The variable $message does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
46
                    $this->makeUrlWithScheme($url, $this->secure),
47
                    $this->secure,
48 8
                    $parameters
49 8
                );
50
51
                if (!$healthy) {
0 ignored issues
show
Bug introduced by
The variable $healthy does not exist. Did you mean $health?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
52
                    return $this->makeResult($healthy, $message);
0 ignored issues
show
Bug introduced by
The variable $healthy does not exist. Did you mean $health?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
53 8
                }
54 8
            }
55 8
56
            return $this->makeHealthyResult();
57 8
        } catch (\Exception $exception) {
58
            report($exception);
59
60
            return $this->makeResultFromException($exception);
61
        }
62
    }
63
64
    /**
65
     *  Get array of resource urls.
66 8
     *
67
     * @return array
68 8
     */
69 8
    private function getResourceUrlArray()
70
    {
71
        if (is_a($this->target->urls, Collection::class)) {
72
            return $this->target->urls->toArray();
73
        }
74
75
        return (array) $this->target->urls;
76
    }
77
78
    /**
79
     *  Check web pages.
80
     *
81
     * @param $url
82 8
     * @param bool $ssl
83
     * @return mixed
84 8
     */
85
    private function checkWebPage($url, $ssl = false, $parameters = [])
86 8
    {
87
        try {
88
            $success = $this->requestSuccessful($url, $ssl, $parameters);
89
90
            $message = $this->getErrorMessage();
91
        } catch (\Exception $exception) {
92
            $success = false;
93
94
            $message = "Target: {$url} - ERROR: " . $exception->getMessage();
95
96
            report($exception);
97 8
        }
98
99 8
        return [$success, $success ? '' : $message];
100
    }
101 8
102 8
    /**
103 8
     * Send an http request and fetch the response.
104 8
     *
105
     * @param $url
106
     * @param $ssl
107
     * @return mixed|\Psr\Http\Message\ResponseInterface
108
     * @throws \GuzzleHttp\Exception\GuzzleException
109
     */
110
    private function fetchResponse($url, $ssl, $parameters = [])
111
    {
112
        $this->url = $url;
113
114 8
        return (new Guzzle())->request(
115
            $this->getMethod($parameters),
0 ignored issues
show
Documentation introduced by
$this->getMethod($parameters) is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
116
            $this->url,
117 8
            array_merge($this->getConnectionOptions($ssl), $parameters)
118 8
        );
119 8
    }
120 8
121
    /**
122
     * Get http connection options.
123
     *
124
     * @param $ssl
125
     * @return array
126
     */
127
    private function getConnectionOptions($ssl)
128
    {
129
        return [
130
            'connect_timeout' => $this->getConnectionTimeout(),
131
            'timeout' => $this->getConnectionTimeout(),
132
            'verify' => $ssl,
133
            'on_stats' => $this->onStatsCallback()
134
        ];
135
    }
136
137
    /**
138
     * Get the error message.
139
     *
140
     * @return string
141
     */
142
    private function getErrorMessage()
143
    {
144
        $message = $this->target->resource->timeoutMessage;
145
146 8
        return sprintf(
147
            $message,
148 8
            $this->url,
149
            $this->totalTime,
150
            $this->getRoundtripTimeout()
151
        );
152
    }
153
154
    /**
155
     * The the connection timeout.
156 8
     *
157
     * @return int
158 8
     */
159
    private function getConnectionTimeout()
160
    {
161
        return $this->target->resource->connectionTimeout;
162
    }
163
164
    /**
165
     * The the roundtrip timeout.
166
     *
167
     * @return int
168 8
     */
169
    private function getRoundtripTimeout()
170 8
    {
171 8
        return $this->target->resource->roundtripTimeout;
172 8
    }
173 8
174
    /**
175
     * Make a url with a proper scheme.
176
     *
177
     * @param $url
178
     * @param $secure
179
     * @return mixed
180
     */
181
    private function makeUrlWithScheme($url, $secure)
182 8
    {
183
        return preg_replace(
184
            '|^((https?:)?\/\/)?(.*)|',
185 8
            'http' . ($secure ? 's' : '') . '://\\3',
186 8
            $url
187
        );
188
    }
189
190
    /**
191
     * Guzzle OnStats callback.
192
     *
193
     * @return \Closure
194
     */
195
    private function onStatsCallback()
196
    {
197 8
        return function (TransferStats $stats) {
198
            $this->totalTime = $stats->getTransferTime();
199
        };
200 8
    }
201 8
202
    /**
203
     * Send a request and get the result.
204
     *
205
     * @param $url
206
     * @param $ssl
207
     * @return bool
208
     * @internal param $response
209 8
     */
210
    private function requestSuccessful($url, $ssl, $parameters)
211 8
    {
212
        $response = $this->fetchResponse($url, $ssl, $parameters);
213
214
        if ($response->getStatusCode() >= 400) {
215
            throw new \Exception((string) $response->getBody());
216
        }
217
218
        return !$this->requestTimeout();
219
    }
220
221
    /**
222
     * Check if the request timed out.
223
     *
224
     * @return bool
225
     */
226
    private function requestTimeout()
227
    {
228
        return $this->totalTime > $this->getRoundtripTimeout();
229
    }
230
231
    /**
232
     * Parse URL from config.
233
     *
234
     * @return array
235
     */
236
    protected function parseConfigUrl($data)
237
    {
238
        if (is_string($data)) {
239
            return [$data, []];
240
        }
241
242
        $url = array_keys($data)[0];
243
244
        $parameters = $data[$url];
245
246
        $url = isset($parameters['url']) ? $parameters['url'] : $url;
247
248
        return [$url, $parameters];
249
    }
250
251
    /**
252
     * Get the request method.
253
     *
254
     * @return bool
255
     */
256
    protected function getMethod($parameters)
257
    {
258
        if (!isset($parameters['method'])) {
259
            return 'GET';
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 'GET'; (string) is incompatible with the return type documented by PragmaRX\Health\Checkers\Http::getMethod of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
260
        }
261
262
        return $parameters['method'];
263
    }
264
}
265