PingCommandBuilder::timeout()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
rs 10
1
<?php
2
3
/**
4
 * Ping for Laravel.
5
 *
6
 * This class makes Ping request to a host.
7
 *
8
 * Ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to elicit an ICMP ECHO_RESPONSE from a host or gateway.
9
 *
10
 * @author  Angel Campos <[email protected]>
11
 *
12
 * @requires PHP 8.0
13
 *
14
 * @version  2.1.2
15
 */
16
17
namespace Acamposm\Ping;
18
19
use Acamposm\Ping\Exceptions\InvalidIPAddressException;
20
use Acamposm\Ping\Exceptions\MaxValueException;
21
use Acamposm\Ping\Exceptions\NegativeValueException;
22
use Acamposm\Ping\Exceptions\UnknownOSException;
23
use Acamposm\Ping\Interfaces\PingCommand;
24
25
class PingCommandBuilder implements PingCommand
26
{
27
    protected int $count;
28
    protected ?string $host;
29
    protected float $interval;
30
    protected int $packet_size;
31
    protected int $ttl;
32
    protected int $timeout;
33
    protected int $version;
34
35
    /**-
36
     * PingCommand constructor.
37
     *
38
     * @param string|null $host
39
     * @throws InvalidIPAddressException
40
     */
41
    public function __construct(?string $host = null)
42
    {
43
        if ($this->isValidIPAddress($host)) {
44
            $this->host = $host;
45
            $this->setIPAddressVersion();
46
        } else {
47
            if (str_ends_with($host, '/')) {
0 ignored issues
show
Bug introduced by
It seems like $host can also be of type null; however, parameter $haystack of str_ends_with() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

47
            if (str_ends_with(/** @scrutinizer ignore-type */ $host, '/')) {
Loading history...
48
                $host = substr($host, 0, -1);
0 ignored issues
show
Bug introduced by
It seems like $host can also be of type null; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

48
                $host = substr(/** @scrutinizer ignore-type */ $host, 0, -1);
Loading history...
49
            }
50
51
            // We assume that is an URL...
52
            //TODO: Needs URL validation
53
            $pattern = '/^http:\/\/|^https:\/\//';
54
55
            if (preg_match($pattern, $host)) {
0 ignored issues
show
Bug introduced by
It seems like $host can also be of type null; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

55
            if (preg_match($pattern, /** @scrutinizer ignore-type */ $host)) {
Loading history...
56
                $this->host = preg_replace($pattern, '', $host);
57
            } else {
58
                $this->host = $host;
59
            }
60
        }
61
62
        $this->count = config('ping.count');
63
        $this->interval = config('ping.interval');
64
        $this->packet_size = config('ping.packet_size');
65
        $this->timeout = config('ping.timeout');
66
        $this->ttl = config('ping.ttl');
67
    }
68
69
    /**
70
     * Validates an IP Address.
71
     *
72
     * @param string|null $ip_address
73
     *
74
     * @throws InvalidIPAddressException
75
     *
76
     * @return bool
77
     */
78
    private function isValidIPAddress(?string $ip_address = null): bool
79
    {
80
        return IPAddress::Validate($ip_address);
0 ignored issues
show
Bug introduced by
It seems like $ip_address can also be of type null; however, parameter $ip_address of Acamposm\Ping\IPAddress::Validate() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

80
        return IPAddress::Validate(/** @scrutinizer ignore-type */ $ip_address);
Loading history...
81
    }
82
83
    /**
84
     * Select the appropriate IP version.
85
     */
86
    private function setIPAddressVersion(): void
87
    {
88
        if (strpos($this->host, IPAddress::IPV4_SEPARATOR) > 0) {
0 ignored issues
show
Bug introduced by
It seems like $this->host can also be of type null; however, parameter $haystack of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

88
        if (strpos(/** @scrutinizer ignore-type */ $this->host, IPAddress::IPV4_SEPARATOR) > 0) {
Loading history...
89
            $this->useIPv4();
90
        } elseif (strpos($this->host, IPAddress::IPV6_SEPARATOR) > 0) {
91
            $this->useIPv6();
92
        }
93
    }
94
95
    /**
96
     * Set IP protocol version 4.
97
     */
98
    private function useIPv4(): void
99
    {
100
        $this->version = 4;
101
    }
102
103
    /**
104
     * Set IP protocol version 6.
105
     */
106
    private function useIPv6(): void
107
    {
108
        $this->version = 6;
109
    }
110
111
    /**
112
     * Stop after sending count ECHO_REQUEST packets. With deadline option, ping
113
     * waits for count ECHO_REPLY packets, until the timeout expires.
114
     *
115
     * @param int $count
116
     *
117
     * @throws NegativeValueException
118
     *
119
     * @return PingCommandBuilder
120
     */
121
    public function count(int $count): PingCommandBuilder
122
    {
123
        if ($count < 0) {
124
            throw new NegativeValueException();
125
        }
126
127
        $this->count = $count;
128
129
        return $this;
130
    }
131
132
    /**
133
     * Wait interval seconds between sending each packet. The default is to wait
134
     * for one second between each packet normally, or not to wait in flood mode.
135
     * Only super-user may set interval to values less than 0.2 seconds.
136
     *
137
     * @param float $interval
138
     *
139
     * @return PingCommandBuilder
140
     */
141
    public function interval(float $interval): PingCommandBuilder
142
    {
143
        $this->interval = $interval;
144
145
        return $this;
146
    }
147
148
    /**
149
     * Specifies the number of data bytes to be sent. The default is 56, which
150
     * translates into 64 ICMP data bytes when combined with the 8 bytes of ICMP
151
     * header data.
152
     *
153
     * @param int $packet_size
154
     *
155
     * @return PingCommandBuilder
156
     */
157
    public function packetSize(int $packet_size): PingCommandBuilder
158
    {
159
        $this->packet_size = $packet_size;
160
161
        return $this;
162
    }
163
164
    /**
165
     * ping only. Set the IP Time to Live.
166
     *
167
     * @param int $ttl
168
     *
169
     * @throws MaxValueException
170
     *
171
     * @return PingCommandBuilder
172
     */
173
    public function ttl(int $ttl): PingCommandBuilder
174
    {
175
        if ($ttl > 255) {
176
            throw new MaxValueException();
177
        }
178
179
        $this->ttl = $ttl;
180
181
        return $this;
182
    }
183
184
    /**
185
     * Time to wait for a response. The option affects only timeout in absence
186
     * of any responses, otherwise ping waits for two RTTs.
187
     * (Seconds for Linux OS, Milliseconds for Windows).
188
     *
189
     * @param int $timeout
190
     *
191
     * @return PingCommandBuilder
192
     */
193
    public function timeout(int $timeout): PingCommandBuilder
194
    {
195
        $this->timeout = $timeout;
196
197
        return $this;
198
    }
199
200
    /**
201
     * Returns the Linux Ping Command.
202
     *
203
     * @return string
204
     */
205
    private function getLinuxCommand(): string
206
    {
207
        $command = ['ping -n'];
208
209
        (!isset($this->version)) ?: array_push($command, '-'.$this->version);
210
        (!isset($this->count)) ?: array_push($command, '-c '.$this->count);
211
        (!isset($this->interval)) ?: array_push($command, '-i '.$this->interval);
212
        (!isset($this->packet_size)) ?: array_push($command, '-s '.$this->packet_size);
213
        (!isset($this->timeout)) ?: array_push($command, '-W '.$this->timeout);
214
        (!isset($this->ttl)) ?: array_push($command, '-t '.$this->ttl);
215
216
        $command[] = $this->host;
217
218
        return implode(' ', $command);
219
    }
220
221
    /**
222
     * Returns the OSX Ping Command.
223
     *
224
     * @return string
225
     */
226
    private function getOSXCommand(): string
227
    {
228
        $command = ['ping'];
229
230
        // (!isset($this->version)) ?: array_push($command, '-'.$this->version);
231
        (!isset($this->count)) ?: array_push($command, '-c '.$this->count);
232
        (!isset($this->interval)) ?: array_push($command, '-i '.$this->interval);
233
        (!isset($this->packet_size)) ?: array_push($command, '-s '.$this->packet_size);
234
        (!isset($this->timeout)) ?: array_push($command, '-t '.$this->timeout);
235
        (!isset($this->ttl)) ?: array_push($command, '-m '.$this->ttl);
236
237
        $command[] = $this->host;
238
239
        return implode(' ', $command);
240
    }
241
242
    /**
243
     * Returns the Windows Ping Command.
244
     *
245
     * @return string
246
     */
247
    private function getWindowsCommand(): string
248
    {
249
        $command = ['ping'];
250
251
        (!isset($this->version)) ?: array_push($command, '-'.$this->version);
252
        (!isset($this->count)) ?: array_push($command, '-n '.$this->count);
253
        (!isset($this->packet_size)) ?: array_push($command, '-l '.$this->packet_size);
254
        (!isset($this->timeout)) ?: array_push($command, '-w '.($this->timeout * 1000));
255
        (!isset($this->ttl)) ?: array_push($command, '-i '.$this->ttl);
256
257
        $command[] = $this->host;
258
259
        return implode(' ', $command);
260
    }
261
262
    /**
263
     * Return an object with the options.
264
     *
265
     * @return object
266
     */
267
    public function getOptions(): object
268
    {
269
        $options = [
270
            'host' => $this->host,
271
        ];
272
273
        (!isset($this->count)) ?: $options['count'] = $this->count;
274
        (!isset($this->interval)) ?: $options['interval'] = $this->interval;
275
        (!isset($this->packet_size)) ?: $options['packet_size'] = $this->packet_size;
276
        (!isset($this->timeout)) ?: $options['timeout'] = $this->timeout;
277
        (!isset($this->ttl)) ?: $options['ttl'] = $this->ttl;
278
        (!isset($this->version)) ?: $options['version'] = $this->version;
279
280
        return (object) $options;
281
    }
282
283
    /**
284
     * Return the Ping Command.
285
     *
286
     * @throws UnknownOSException
287
     *
288
     * @return string
289
     */
290
    public function get(): string
291
    {
292
        if (System::isLinux()) {
293
            return $this->getLinuxCommand();
294
        }
295
296
        if (System::isOSX()) {
297
            return $this->getOSXCommand();
298
        }
299
300
        if (System::isWindows()) {
301
            return $this->getWindowsCommand();
302
        }
303
304
        throw new UnknownOSException();
305
    }
306
}
307