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); |
|
|
|
|
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); |
|
|
|
|
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); |
|
|
|
|
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
|
|
|
|