Passed
Push — master ( ced321...095989 )
by Angel
02:40
created

PingParserForLinux   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 212
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 72
c 3
b 1
f 0
dl 0
loc 212
rs 10
wmc 26

12 Methods

Rating   Name   Duplication   Size   Complexity  
A cleanStatisticsRecord() 0 10 1
A __construct() 0 14 2
A parse() 0 21 4
A parseStatistics() 0 25 5
A setStatistics() 0 3 1
A getSequence() 0 26 3
A parseRoundTripTime() 0 15 2
A getHostStatus() 0 3 2
A setRoundTripTime() 0 3 1
A setSequence() 0 3 1
A setHostStatus() 0 3 1
A isUnreachable() 0 11 3
1
<?php
2
3
namespace Acamposm\Ping\Parsers;
4
5
use Acamposm\Ping\Interfaces\PingParserInterface;
6
7
final class PingParserForLinux extends PingParser implements PingParserInterface
8
{
9
    protected bool $is_unreachable;
10
11
    /**
12
     * PingParserForLinux constructor.
13
     *
14
     * @param array $ping
15
     */
16
    public function __construct(array $ping)
17
    {
18
        parent::__construct($ping);
19
20
        $this->is_unreachable = self::isUnreachable($ping);
0 ignored issues
show
Bug Best Practice introduced by
The method Acamposm\Ping\Parsers\Pi...rLinux::isUnreachable() is not static, but was called statically. ( Ignorable by Annotation )

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

20
        /** @scrutinizer ignore-call */ 
21
        $this->is_unreachable = self::isUnreachable($ping);
Loading history...
21
22
        $this->host_status = 'Unreachable';
23
24
        $this->setStatistics($ping[count($ping) - 2]);
25
26
        if ($this->is_unreachable === false) {
27
            $this->setRoundTripTime($ping[count($ping) - 1]);
28
            $this->setSequence();
29
            $this->setHostStatus();
30
        }
31
    }
32
33
    private function cleanStatisticsRecord(string $row): array
34
    {
35
        $search = explode(
36
            '|',
37
            'packets|transmitted|received|+|errors|%|packet|loss|time|ms'
38
        );
39
40
        $row = trim(str_replace($search, null, $row));
41
42
        return array_map('trim', explode(', ', $row));
43
    }
44
45
    private function isUnreachable($ping)
46
    {
47
        $unreachable = false;
48
49
        foreach($ping as $row) {
50
            if ($unreachable = strpos($row, '100% packet loss')) {
51
                break;
52
            }
53
        }
54
55
        return $unreachable !== false;
56
    }
57
58
    /**
59
     * Get the host status.
60
     *
61
     * @return string
62
     */
63
    private function getHostStatus(): string
64
    {
65
        return ($this->statistics['packet_loss'] < 100) ? 'Ok' : 'Unreachable';
66
    }
67
68
    /**
69
     * Return an array with the Ping sequence and latency.
70
     *
71
     * @return array
72
     */
73
    private function getSequence(): array
74
    {
75
        $ping = $this->raw;
76
77
        // Remove unnecessary index
78
        unset($ping[0]);
79
        unset($ping[count($ping) - 4]);
80
        unset($ping[count($ping) - 3]);
81
        unset($ping[count($ping) - 2]);
82
        unset($ping[count($ping) - 1]);
83
84
        $sequence = [];
85
86
        foreach ($ping as $row) {
87
            if (strpos('Unreachable', $row) !== false) {
88
                $data = explode(': ', str_replace(' ms', '', $row));
89
                $items = explode(' ', $data[1]);
90
91
                $key = (int) explode('=', $items[0])[1];
92
                $value = (float) explode('=', $items[2])[1];
93
94
                $sequence[$key] = $value;
95
            }
96
        }
97
98
        return $sequence;
99
    }
100
101
    /**
102
     * Return an object with Ping Round Trip Time.
103
     *
104
     * @param string $row
105
     * @return array
106
     */
107
    private function parseRoundTripTime(string $row): array
108
    {
109
        if (strpos($row, 'rtt') === false) {
110
            return [];
111
        }
112
113
        $row = trim(str_replace(['ms', 'rtt'], null, $row));
114
115
        $rtt = explode(' = ', $row);
116
117
        $keys = explode('/', $rtt[0]);
118
119
        $values = array_map('floatval', explode('/', $rtt[1]));
120
121
        return array_combine($keys, $values);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_combine($keys, $values) could return the type false which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
122
    }
123
124
    /**
125
     * Return an object with Ping Statistics.
126
     *
127
     * @param string $row
128
     * @return array
129
     */
130
    private function parseStatistics(string $row): array
131
    {
132
        $statistics = self::cleanStatisticsRecord($row);
0 ignored issues
show
Bug Best Practice introduced by
The method Acamposm\Ping\Parsers\Pi...cleanStatisticsRecord() is not static, but was called statically. ( Ignorable by Annotation )

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

132
        /** @scrutinizer ignore-call */ 
133
        $statistics = self::cleanStatisticsRecord($row);
Loading history...
133
134
        $results = [
135
            'packets_transmitted' => (int) $statistics[0],
136
            'packets_received' => (int) $statistics[1],
137
            'packets_lost' => (int) ($statistics[0] - $statistics[1]),
138
        ];
139
140
        if (count($statistics) === 5 && $this->is_unreachable) {
141
            $results['errors'] = (int) $statistics[2];
142
        }
143
144
        if (count($statistics) === 5) {
145
            $results['packet_loss'] = (float) $statistics[3];
146
            $results['time'] = (int) $statistics[4];
147
        }
148
149
        if (count($statistics) === 4) {
150
            $results['packet_loss'] = (float) $statistics[2];
151
            $results['time'] = (int) $statistics[3];
152
        }
153
154
        return $results;
155
    }
156
157
    /**
158
     * Set the host status.
159
     */
160
    private function setHostStatus(): void
161
    {
162
        $this->host_status = $this->getHostStatus();
163
    }
164
165
    /**
166
     * Set the Round Trip Time statistics.
167
     *
168
     * @param string $rtt
169
     */
170
    private function setRoundTripTime(string $rtt): void
171
    {
172
        $this->round_trip_time = $this->parseRoundTripTime($rtt);
173
    }
174
175
    /**
176
     * Set the Ping sequence.
177
     */
178
    private function setSequence(): void
179
    {
180
        $this->sequence = $this->getSequence();
181
    }
182
183
    /**
184
     * Set the Statistics.
185
     *
186
     * @param string $statistics
187
     */
188
    private function setStatistics(string $statistics): void
189
    {
190
        $this->statistics = $this->parseStatistics($statistics);
191
    }
192
193
    /**
194
     * Return the Ping execution result parsed as object.
195
     *
196
     * @return object
197
     */
198
    public function parse(): object
199
    {
200
        $parsed = [
201
            'host_status' => $this->host_status,
202
            'raw' => (object) $this->raw,
203
        ];
204
205
        if (count($this->round_trip_time) > 0) {
206
            $parsed['latency'] = $this->round_trip_time['avg'];
207
            $parsed['rtt'] = (object) $this->round_trip_time;
208
        }
209
210
        if (count($this->sequence) > 0) {
211
            $parsed['sequence'] = (object) $this->sequence;
212
        }
213
214
        if (count($this->statistics) > 0) {
215
            $parsed['statistics'] = (object) $this->statistics;
216
        }
217
218
        return (object) $parsed;
219
    }
220
}
221