Passed
Pull Request — master (#34)
by
unknown
02:48
created

PingParserForNix::setSequence()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
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\Parsers;
18
19
use Acamposm\Ping\System;
20
21
final class PingParserForNix extends PingParser
22
{
23
    protected bool $is_unreachable;
24
25
    /**
26
     * PingParserForNix constructor.
27
     *
28
     * @param array $ping
29
     */
30
    public function __construct(array $ping)
31
    {
32
        parent::__construct($ping);
33
34
        $this->is_unreachable = $this->isUnreachable($ping);
35
36
        $this->host_status = 'Unreachable';
37
38
        if (preg_match('/^--- (.+) ---$/i', $ping[count($ping) - 2])) {
39
            $this->setStatistics($ping[count($ping) - 1]);
40
41
            if ($this->is_unreachable === false) {
42
                // $this->setRoundTripTime($ping[count($ping)-1]);
43
                $this->setSequence();
44
                $this->setHostStatus();
45
            }
46
        } else {
47
            $this->setStatistics($ping[count($ping) - 2]);
48
49
            if ($this->is_unreachable === false) {
50
                $this->setRoundTripTime($ping[count($ping) - 1]);
51
                $this->setSequence();
52
                $this->setHostStatus();
53
            }
54
        }
55
    }
56
57
    private function cleanStatisticsRecord(string $row): array
58
    {
59
        $search = explode(
60
            '|',
61
            'packets|transmitted|received|+|errors|%|packet|loss|time|ms'
62
        );
63
64
        $row = trim(str_replace($search, '', $row));
65
66
        return array_map('trim', explode(', ', $row));
67
    }
68
69
    private function isUnreachable($ping): bool
70
    {
71
        $unreachable = false;
72
73
        foreach ($ping as $row) {
74
            if ($unreachable === strpos($row, '100% packet loss')) {
75
                break;
76
            }
77
        }
78
79
        return $unreachable !== false;
80
    }
81
82
    /**
83
     * Get the host status.
84
     *
85
     * @return string
86
     */
87
    private function getHostStatus(): string
88
    {
89
        return ($this->statistics[System::isLinux() ? 'packet_loss' : 'packets_lost'] < 100) ? 'Ok' : 'Unreachable';
90
    }
91
92
    /**
93
     * Return an array with the Ping sequence and latency.
94
     *
95
     * @return array
96
     */
97
    private function getSequence(): array
98
    {
99
        $ping = $this->results;
100
101
        // Remove unnecessary index
102
        unset($ping[0]);
103
        unset($ping[count($ping) - 4]);
104
        unset($ping[count($ping) - 3]);
105
        unset($ping[count($ping) - 2]);
106
        unset($ping[count($ping) - 1]);
107
108
        $sequence = [];
109
110
        foreach ($ping as $row) {
111
            if (str_contains($row, 'Unreachable') && !empty($row)) {
112
                $data = explode(': ', str_replace(' ms', '', $row));
113
                $items = explode(' ', $data[1]);
114
115
                $key = (int) explode('=', $items[0])[1];
116
                $value = (float) explode('=', $items[2])[1];
117
118
                $sequence[$key] = $value;
119
            }
120
        }
121
122
        return $sequence;
123
    }
124
125
    /**
126
     * Return an object with Ping Round Trip Time.
127
     *
128
     * @param string $row
129
     *
130
     * @return array
131
     */
132
    private function parseRoundTripTime(string $row): array
133
    {
134
        if (!str_contains($row, 'rtt')) {
135
            return [];
136
        }
137
138
        $row = trim(str_replace(['ms', System::isLinux() ? 'rtt' : 'round-trip'], '', $row));
139
140
        $rtt = explode(' = ', $row);
141
142
        $keys = explode('/', $rtt[0]);
143
144
        $values = array_map('floatval', explode('/', $rtt[1]));
145
146
        return array_combine($keys, $values);
147
    }
148
149
    /**
150
     * Return an object with Ping Statistics.
151
     *
152
     * @param string $row
153
     *
154
     * @return array
155
     */
156
    private function parseStatistics(string $row): array
157
    {
158
        $statistics = $this->cleanStatisticsRecord($row);
159
160
        $results = [
161
            'packets_transmitted' => (int) $statistics[0],
162
            'packets_received'    => (int) $statistics[1],
163
            'packets_lost'        => (int) ($statistics[0] - $statistics[1]),
164
        ];
165
166
        if (count($statistics) === 5 && $this->is_unreachable) {
167
            $results['errors'] = (int) $statistics[2];
168
        }
169
170
        if (count($statistics) === 5) {
171
            $results['packet_loss'] = (float) $statistics[3];
172
            $results['time'] = (int) $statistics[4];
173
        }
174
175
        if (count($statistics) === 4) {
176
            $results['packet_loss'] = (float) $statistics[2];
177
            $results['time'] = (int) $statistics[3];
178
        }
179
180
        return $results;
181
    }
182
183
    /**
184
     * Set the host status.
185
     */
186
    private function setHostStatus(): void
187
    {
188
        $this->host_status = $this->getHostStatus();
189
    }
190
191
    /**
192
     * Set the Round Trip Time statistics.
193
     *
194
     * @param string $rtt
195
     */
196
    private function setRoundTripTime(string $rtt): void
197
    {
198
        $this->round_trip_time = $this->parseRoundTripTime($rtt);
199
    }
200
201
    /**
202
     * Set the Ping sequence.
203
     */
204
    private function setSequence(): void
205
    {
206
        $this->sequence = $this->getSequence();
207
    }
208
209
    /**
210
     * Set the Statistics.
211
     *
212
     * @param string $statistics
213
     */
214
    private function setStatistics(string $statistics): void
215
    {
216
        $this->statistics = $this->parseStatistics($statistics);
217
    }
218
219
    /**
220
     * Return the Ping execution result parsed as object.
221
     *
222
     * @return object
223
     */
224
    public function parse(): object
225
    {
226
        $parsed = [
227
            'host_status' => $this->host_status,
228
            'raw'         => (object) $this->results,
229
        ];
230
231
        if (count($this->round_trip_time) > 0) {
232
            $parsed['latency'] = $this->round_trip_time['avg'];
233
            $parsed['rtt'] = (object) $this->round_trip_time;
234
        }
235
236
        if (count($this->sequence) > 0) {
237
            $parsed['sequence'] = (object) $this->sequence;
238
        }
239
240
        if (count($this->statistics) > 0) {
241
            $parsed['statistics'] = (object) $this->statistics;
242
        }
243
244
        return (object) $parsed;
245
    }
246
}
247