Test Failed
Branch master (af3280)
by Joe
01:53
created

cisco::show_int()   D

Complexity

Conditions 26
Paths 26

Size

Total Lines 182
Code Lines 172

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
cc 26
eloc 172
c 7
b 0
f 0
nc 26
nop 1
dl 0
loc 182
rs 4.5382

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * CISCO Switch Interface Class
4
 * Basically this is a wrapper to do and parse things from IOS.
5
 * Links I might find helpful in improving this class:
6
 *    http://www.networker.gr/index.php/2011/03/parsing-the-cisco-ios-configuration/
7
 *    http://technologyordie.com/parsing-cisco-show-command-output
8
 *    http://packetpushers.net/rocking-your-show-commands-with-regex/
9
 * Based on code from http://www.soucy.org/project/cisco/
10
 *
11
 * @author Joe Huss <[email protected]>
12
 * @version $Revision: 58 $
13
 * @copyright 2017
14
 * @package MyAdmin
15
 * @category Network
16
 */
17
18
/**
19
 * cisco
20
 *
21
 * @access public
22
 */
23
class cisco {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
24
	/**
25
	 * @var bool
26
	 */
27
	public $autoconnect = true; // Sets whether or not exec() will automatically connect() if needed
28
	/**
29
	 * @var int
30
	 */
31
	public $min_timeout = 300; // sets a minimum timeout, 0 or false to disable
32
	/**
33
	 * @var bool
34
	 */
35
	public $connected = FALSE; // True/False Whether or not you are currently connected
36
	/**
37
	 * @var
38
	 */
39
	private $_hostname; // SSH Connection Hostname
40
	/**
41
	 * @var
42
	 */
43
	private $_username; // SSH Connection Username
44
	/**
45
	 * @var
46
	 */
47
	private $_password; // SSH Connection Password
48
	/**
49
	 * @var int
50
	 */
51
	private $_port; // SSH Connection Port
52
	/**
53
	 * @var
54
	 */
55
	private $_motd; // MOTD / Message of the day / Banner
56
	/**
57
	 * @var
58
	 */
59
	private $_prompt; // Prompt
60
	/**
61
	 * @var
62
	 */
63
	private $_ssh; // SSH Connection Resource
64
	/**
65
	 * @var
66
	 */
67
	private $_stream; // Data Stream
68
	/**
69
	 * @var
70
	 */
71
	private $_data; // Formatted Response
72
	/**
73
	 * @var
74
	 */
75
	private $_response; // Raw Response
76
77
	/**
78
	 * @param     $hostname
79
	 * @param     $username
80
	 * @param     $password
81
	 * @param int $port
82
	 */
83
	public function __construct($hostname, $username, $password, $port = 22) {
84
		$this->_hostname = $hostname;
85
		$this->_username = $username;
86
		$this->_password = $password;
87
		$this->_port = $port;
88
		if ($this->min_timeout && ini_get('default_socket_timeout') < $this->min_timeout)
89
			ini_set('default_socket_timeout', $this->min_timeout);
90
	}
91
92
	/**
93
	 * @param     string $string
94
	 * @param int $index
95
	 * @return string
96
	 */
97
	public function _string_shift(&$string, $index = 1) {
98
		$substr = mb_substr($string, 0, $index);
99
		$string = mb_substr($string, $index);
100
		return $substr;
101
	}
102
103
	/**
104
	 * Returns the output of an interactive shell
105
	 * Gathers output from a shell until $pattern is met, Pattern is a regular string
106
	 * unless $regex = true, then it matches it with preg_match as a regular expression.
107
	 *
108
	 * @param $pattern string the string or the pattern to match
109
	 * @param $regex bool Whether or not we are trying to match a regex pattern or just a simple string
110
	 * @return String
111
	 * @access public
112
	 */
113
	public function read($pattern = '', $regex = FALSE) {
114
		//usleep(1000);
115
		$this->_response = '';
116
		$match = $pattern;
117
		$i = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $i is dead and can be removed.
Loading history...
118
		while (!feof($this->_stream)) {
119
			if ($regex) {
120
				preg_match($pattern, $this->_response, $matches);
121
				//echo 'M:'.print_r($matches, TRUE).'<br>';
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
122
				$match = isset($matches[0]) ? $matches[0] : [];
123
			}
124
			$pos = !empty($match) ? mb_strpos($this->_response, $match) : false;
125
			//echo ++$i . "POS:".var_export($pos, TRUE).'<br>';
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
126
			if ($pos !== FALSE) {
127
				//echo "$match Matching $pattern @ $pos <br>";
128
				return $this->_string_shift($this->_response, $pos + mb_strlen($match));
129
			}
130
			usleep(1000);
131
			$response = fgets($this->_stream);
132
			//echo "R$i:$response<br>";
133
			if (is_bool($response)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
134
				//echo "Return B $response::".$this->_response."<br>";
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
135
				//					return $response ? $this->_string_shift($this->_response, mb_strlen($this->_response)) : false;
0 ignored issues
show
Unused Code Comprehensibility introduced by
61% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
136
			}
137
			$this->_response .= $response;
138
		}
139
		echo 'FEOF !!!!<br>';
140
		return $this->_response;
141
	}
142
143
	/**
144
	 * @param string $cmd
145
	 */
146
	public function write($cmd) {
147
		fwrite($this->_stream, $cmd);
148
	}
149
150
	/**
151
	 * @return bool
152
	 */
153
	public function connect() {
154
		//echo "Connecting to " . $this->_hostname . "<br>";
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
155
		$this->_ssh = ssh2_connect($this->_hostname, $this->_port);
156
		if ($this->_ssh === FALSE)
0 ignored issues
show
introduced by
The condition $this->_ssh === FALSE is always false.
Loading history...
157
			return false;
158
		ssh2_auth_password($this->_ssh, $this->_username, $this->_password);
159
		$this->_stream = ssh2_shell($this->_ssh);
160
		$this->connected = true;
161
		$this->parse_motd_and_prompt();
162
		return true;
163
	}
164
165
	/**
166
	 *
167
	 */
168
	public function parse_motd_and_prompt() {
169
		$this->_motd = trim($this->read('/.*[>|#]/', TRUE));
170
		$this->write("\n");
171
		$this->_prompt = trim($this->read('/.*[>|#]/', TRUE));
172
		$length = mb_strlen($this->_prompt);
173
		if (mb_substr($this->_motd, -$length) == $this->_prompt)
174
			$this->_motd = mb_substr($this->_motd, 0, -$length);
175
		//echo "MOTD:".$this->_motd."<br>";
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
176
		//echo "Prompt:".$this->_prompt.'<br>';
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
177
		return true;
178
		sleep(1);
0 ignored issues
show
Unused Code introduced by
sleep(1) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
179
		$this->_motd = '';
180
		while ($this->_response = fgets($this->_stream))
181
			$this->_motd .= $this->_response;
182
		$this->_motd = trim($this->_motd);
183
		fwrite($this->_stream, "\n");
184
		$this->_response = stream_get_contents($this->_stream);
185
		//stream_set_blocking($this->_stream, FALSE);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
186
		$this->_prompt = trim($this->_response);
187
		/*			sleep (1);
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
188
		while ($this->_response = fgets($this->_stream))
189
			$this->_prompt .= $this->_response;
190
		$this->_prompt = trim($this->_prompt);*/
191
		echo 'MOTD:'.$this->_motd.'<br>';
192
		echo 'Prompt:'.$this->_prompt.'<br>';
193
		$length = mb_strlen($this->_prompt);
194
		if (mb_substr($this->_motd, -$length) == $this->_prompt) {
195
			//echo "Found Prompt<br>";
196
			$this->_motd = mb_substr($this->_motd, 0, -$length);
197
		}
198
		//echo "MOTD:".$this->_motd . "<br>";
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
199
		echo 'Prompt:'.$this->_prompt.'<br>';
200
		/*			$this->_stream = ssh2_exec($this->_ssh, "#");
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
201
		stream_set_blocking($this->_stream, TRUE);
202
		$this->_response = stream_get_contents($this->_stream);
203
		$this->_data = $this->_response;
204
		stream_set_blocking($this->_stream, FALSE);
205
		var_dump($this->_response);
206
		*/
207
	}
208
209
	/**
210
	 * @param string $cmd
211
	 * @return string
212
	 */
213
	public function exec($cmd) {
214
		if ($this->autoconnect === true && $this->connected === FALSE)
215
			$this->connect();
216
		if (mb_substr($cmd, -1) != "\n") {
217
			//error_log("Adding NEWLINE Character To SSH2 Command $cmd", __LINE__, __FILE__);
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
218
			$cmd .= "\n";
219
		}
220
		$this->_data = FALSE;
221
		fwrite($this->_stream, $cmd);
222
		$this->_response = trim($this->read($this->_prompt));
223
		$length = mb_strlen($this->_prompt);
224
		if (mb_substr($this->_response, -$length) == $this->_prompt) {
225
			//echo "Found Prompt<br>";
226
			$this->_response = mb_substr($this->_response, 0, -$length);
227
		}
228
		$this->_data = $this->_response;
229
		//stream_set_blocking($this->_stream, FALSE);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
230
		//if (mb_strpos($this->_data, '% Invalid input detected') !== FALSE) $this->_data = FALSE;
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
231
		return $this->_data;
232
	}
233
234
	/**
235
	 * @return string
236
	 */
237
	public function get_response() {
238
		return $this->_response;
239
	}
240
241
	/**
242
	 *
243
	 */
244
	public function disconnect() {
245
		//ssh2_exec($this->_ssh, 'quit');
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
246
		$this->connected = FALSE;
247
	}
248
249
	/**
250
	 *
251
	 */
252
	public function __destruct() {
253
		if ($this->connected === true)
254
			$this->disconnect();
255
	}
256
257
	/**
258
	 * @param $int
259
	 * @return string
260
	 */
261
	public function show_int_config($int) {
262
		// Enabled Only
263
		//if (mb_strpos($this->_prompt, '#') === FALSE)
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
264
		//	die('Error: User must be enabled to use show_int_config()'.PHP_EOL);
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
265
		$this->exec('show run int '.$int);
266
		return $this->show_int_config_parser();
267
	}
268
269
	/**
270
	 * @return string
271
	 */
272
	public function show_int_config_parser() {
273
		$this->_data = explode("\r\n", $this->_data);
274
		for ($i = 0; $i < 5; $i++)
275
			array_shift($this->_data);
276
		for ($i = 0; $i < 2; $i++)
277
			array_pop($this->_data);
278
		$this->_data = implode("\n", $this->_data);
279
		return $this->_data;
280
	}
281
282
	/**
283
	 * @return array
284
	 */
285
	public function show_int_status() {
286
		$result = [];
287
		$this->exec('show int status');
288
		$this->_data = explode("\r\n", $this->_data);
289
		for ($i = 0; $i < 2; $i++)
290
			array_shift($this->_data);
291
		array_pop($this->_data);
292
		$pos = mb_strpos($this->_data[0], 'Status');
293
		foreach ($this->_data as $entry) {
294
			$temp = trim($entry);
295
			if (mb_strlen($temp) > 1 && $temp[2] != 'r' && $temp[0] != '-') {
296
				$entry = [];
297
				$entry['interface'] = mb_substr($temp, 0, mb_strpos($temp, ' '));
298
				$entry['description'] = trim(mb_substr($temp, mb_strpos($temp, ' ') + 1, $pos - mb_strlen($entry['interface']) - 1));
299
				$temp = mb_substr($temp, $pos);
300
				/** @noinspection PrintfScanfArgumentsInspection */
301
				$temp = sscanf($temp, '%s %s %s %s %s %s');
302
				$entry['status'] = $temp[0];
303
				$entry['vlan'] = $temp[1];
304
				$entry['duplex'] = $temp[2];
305
				$entry['speed'] = $temp[3];
306
				$entry['type'] = trim($temp[4].' '.$temp[5]);
307
				$result[] = $entry;
308
			} // if
309
		} // foreach
310
		$this->_data = $result;
311
		return $this->_data;
312
	}
313
314
	/**
315
	 * @return array
316
	 */
317
	public function show_log() {
318
		// Enabled Only
319
		if (mb_strpos($this->_prompt, '#') === FALSE)
320
			die('Error: User must be enabled to use show_log()'.PHP_EOL);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
321
		$result = [];
322
		$this->exec('sh log | inc %');
323
		$this->_data = explode("\r\n", $this->_data);
324
		array_shift($this->_data);
325
		array_pop($this->_data);
326
		foreach ($this->_data as $entry) {
327
			$temp = trim($entry);
328
			$entry = [];
329
			$entry['timestamp'] = mb_substr($temp, 0, mb_strpos($temp, '%') - 2);
330
			if ($entry['timestamp'][0] == '.' || $entry['timestamp'][0] == '*')
331
				$entry['timestamp'] = mb_substr($entry['timestamp'], 1);
332
			$temp = mb_substr($temp, mb_strpos($temp, '%') + 1);
333
			$entry['type'] = mb_substr($temp, 0, mb_strpos($temp, ':'));
334
			$temp = mb_substr($temp, mb_strpos($temp, ':') + 2);
335
			$entry['message'] = $temp;
336
			$result[] = $entry;
337
		} // foreach
338
		$this->_data = $result;
339
		return $this->_data;
340
	}
341
342
	/**
343
	 * @param $int
344
	 * @return array
345
	 */
346
	public function show_int($int) {
347
		$result = [];
348
		$this->exec('show int '.$int);
349
		$this->_data = explode("\r\n", $this->_data);
350
		foreach ($this->_data as $entry) {
351
			$entry = trim($entry);
352
			if (mb_strpos($entry, 'line protocol') !== FALSE) {
353
				$result['interface'] = mb_substr($entry, 0, mb_strpos($entry, ' '));
354
				if (mb_strpos($entry, 'administratively') !== FALSE) {
355
					$result['status'] = 'disabled';
356
				} elseif (mb_substr($entry, mb_strpos($entry, 'line protocol') + 17, 2) == 'up') {
357
					$result['status'] = 'connected';
358
				} else {
359
					$result['status'] = 'notconnect';
360
				} // if .. else
361
			} elseif (mb_strpos($entry, 'Description: ') !== FALSE) {
362
				$entry = explode(':', $entry);
363
				$result['description'] = trim($entry[1]);
364
			} elseif (mb_strpos($entry, 'MTU') !== FALSE) {
365
				$entry = explode(',', $entry);
366
				$entry[0] = trim($entry[0]);
367
				$entry[0] = explode(' ', $entry[0]);
368
				$result['mtu'] = $entry[0][1];
369
				$entry[1] = trim($entry[1]);
0 ignored issues
show
Bug introduced by
It seems like $entry[1] can also be of type array; however, parameter $str of trim() 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

369
				$entry[1] = trim(/** @scrutinizer ignore-type */ $entry[1]);
Loading history...
370
				$entry[1] = explode(' ', $entry[1]);
371
				$result['bandwidth'] = $entry[1][1];
372
				$entry[2] = trim($entry[2]);
373
				$entry[2] = explode(' ', $entry[2]);
374
				$result['dly'] = $entry[2][1];
375
			} elseif (mb_strpos($entry, 'duplex') !== FALSE) {
376
				$entry = explode(',', $entry);
377
				$entry[0] = trim($entry[0]);
378
				$entry[0] = explode(' ', $entry[0]);
379
				$entry[0][0] = explode('-', $entry[0][0]);
380
				$result['duplex'] = strtolower($entry[0][0][0]);
381
				$entry[1] = trim($entry[1]);
0 ignored issues
show
Bug introduced by
It seems like $entry[1] can also be of type array<mixed,mixed|array> and array; however, parameter $str of trim() 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

381
				$entry[1] = trim(/** @scrutinizer ignore-type */ $entry[1]);
Loading history...
382
				if (mb_strpos($entry[1], 'Auto') !== FALSE) {
383
					$result['speed'] = 'auto';
384
				} else {
385
					$result['speed'] = (int)$entry[1];
386
				} // if .. else
387
				$entry[2] = rtrim($entry[2]);
0 ignored issues
show
Bug introduced by
It seems like $entry[2] can also be of type array<mixed,mixed|array> and array; however, parameter $str of rtrim() 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

387
				$entry[2] = rtrim(/** @scrutinizer ignore-type */ $entry[2]);
Loading history...
388
				$result['type'] = mb_substr($entry[2], mb_strrpos($entry[2], ' ') + 1);
389
			} elseif (mb_strpos($entry, 'input rate') !== FALSE) {
390
				$entry = explode(',', $entry);
391
				$result['in_rate'] = mb_substr($entry[0], mb_strpos($entry[0], 'rate') + 5, mb_strrpos($entry[0], ' ') - (mb_strpos($entry[0], 'rate') + 5));
392
				$entry = trim($entry[1]);
393
				$entry = explode(' ', $entry);
394
				$result['in_packet_rate'] = $entry[0];
395
			} elseif (mb_strpos($entry, 'output rate') !== FALSE) {
396
				$entry = explode(',', $entry);
397
				$result['out_rate'] = mb_substr($entry[0], mb_strpos($entry[0], 'rate') + 5, mb_strrpos($entry[0], ' ') - (mb_strpos($entry[0], 'rate') + 5));
398
				$entry = trim($entry[1]);
399
				$entry = explode(' ', $entry);
400
				$result['out_packet_rate'] = $entry[0];
401
			} elseif (mb_strpos($entry, 'packets input') !== FALSE) {
402
				$entry = explode(',', $entry);
403
				$entry[0] = trim($entry[0]);
404
				$entry[0] = explode(' ', $entry[0]);
405
				$result['in_packet'] = $entry[0][0];
406
				$entry[1] = trim($entry[1]);
407
				$entry[1] = explode(' ', $entry[1]);
408
				$result['in'] = $entry[1][0];
409
				if (count($entry) > 2) {
410
					$entry[2] = trim($entry[2]);
411
					$entry[2] = explode(' ', $entry[2]);
412
					$result['no_buffer'] = $entry[2][0];
413
				} // if
414
			} elseif (mb_strpos($entry, 'Received') !== FALSE) {
415
				$entry = explode(',', $entry);
416
				$entry[0] = trim($entry[0]);
417
				$entry[0] = explode(' ', $entry[0]);
418
				$result['broadcast'] = $entry[0][1];
419
				if (count($entry) > 1) {
420
					$entry[1] = trim($entry[1]);
421
					$entry[1] = explode(' ', $entry[1]);
422
					$result['runt'] = $entry[1][0];
423
					$entry[2] = trim($entry[2]);
424
					$entry[2] = explode(' ', $entry[2]);
425
					$result['giant'] = $entry[2][0];
426
					$entry[3] = trim($entry[3]);
427
					$entry[3] = explode(' ', $entry[3]);
428
					$result['throttle'] = $entry[3][0];
429
				} // if
430
			} elseif (mb_strpos($entry, 'CRC') !== FALSE) {
431
				$entry = explode(',', $entry);
432
				$entry[0] = trim($entry[0]);
433
				$entry[0] = explode(' ', $entry[0]);
434
				$result['in_error'] = $entry[0][0];
435
				$entry[1] = trim($entry[1]);
436
				$entry[1] = explode(' ', $entry[1]);
437
				$result['crc'] = $entry[1][0];
438
				$entry[2] = trim($entry[2]);
439
				$entry[2] = explode(' ', $entry[2]);
440
				$result['frame'] = $entry[2][0];
441
				$entry[3] = trim($entry[3]);
442
				$entry[3] = explode(' ', $entry[3]);
443
				$result['overrun'] = $entry[3][0];
444
				$entry[4] = trim($entry[4]);
445
				$entry[4] = explode(' ', $entry[4]);
446
				$result['ignored'] = $entry[4][0];
447
			} elseif (mb_strpos($entry, 'watchdog') !== FALSE) {
448
				$entry = explode(',', $entry);
449
				$entry[0] = trim($entry[0]);
450
				$entry[0] = explode(' ', $entry[0]);
451
				$result['watchdog'] = $entry[0][0];
452
				$entry[1] = trim($entry[1]);
453
				$entry[1] = explode(' ', $entry[1]);
454
				$result['multicast'] = $entry[1][0];
455
				if (count($entry) > 2) {
456
					$entry[2] = trim($entry[2]);
457
					$entry[2] = explode(' ', $entry[2]);
458
					$result['pause_in'] = $entry[2][0];
459
				} // if
460
			} elseif (mb_strpos($entry, 'dribble') !== FALSE) {
461
				$entry = trim($entry);
462
				$entry = explode(' ', $entry);
463
				$result['in_dribble'] = $entry[0];
464
			} elseif (mb_strpos($entry, 'packets output') !== FALSE) {
465
				$entry = explode(',', $entry);
466
				$entry[0] = trim($entry[0]);
467
				$entry[0] = explode(' ', $entry[0]);
468
				$result['out_packet'] = $entry[0][0];
469
				$entry[1] = trim($entry[1]);
470
				$entry[1] = explode(' ', $entry[1]);
471
				$result['out'] = $entry[1][0];
472
				$entry[2] = trim($entry[2]);
473
				$entry[2] = explode(' ', $entry[2]);
474
				$result['underrun'] = $entry[2][0];
475
			} elseif (mb_strpos($entry, 'output errors') !== FALSE) {
476
				$entry = explode(',', $entry);
477
				$entry[0] = trim($entry[0]);
478
				$entry[0] = explode(' ', $entry[0]);
479
				$result['out_error'] = $entry[0][0];
480
				if (count($entry) > 2) {
481
					$entry[1] = trim($entry[1]);
482
					$entry[1] = explode(' ', $entry[1]);
483
					$result['collision'] = $entry[1][0];
484
					$entry[2] = trim($entry[2]);
485
					$entry[2] = explode(' ', $entry[2]);
486
					$result['reset'] = $entry[2][0];
487
				} else {
488
					$entry[1] = trim($entry[1]);
489
					$entry[1] = explode(' ', $entry[1]);
490
					$result['reset'] = $entry[1][0];
491
				} // if .. else
492
			} elseif (mb_strpos($entry, 'babbles') !== FALSE) {
493
				$entry = explode(',', $entry);
494
				$entry[0] = trim($entry[0]);
495
				$entry[0] = explode(' ', $entry[0]);
496
				$result['babble'] = $entry[0][0];
497
				$entry[1] = trim($entry[1]);
498
				$entry[1] = explode(' ', $entry[1]);
499
				$result['late_collision'] = $entry[1][0];
500
				$entry[2] = trim($entry[2]);
501
				$entry[2] = explode(' ', $entry[2]);
502
				$result['deferred'] = $entry[2][0];
503
			} elseif (mb_strpos($entry, 'lost carrier') !== FALSE) {
504
				$entry = explode(',', $entry);
505
				$entry[0] = trim($entry[0]);
506
				$entry[0] = explode(' ', $entry[0]);
507
				$result['lost_carrier'] = $entry[0][0];
508
				$entry[1] = trim($entry[1]);
509
				$entry[1] = explode(' ', $entry[1]);
510
				$result['no_carrier'] = $entry[1][0];
511
				if (count($entry) > 2) {
512
					$entry[2] = trim($entry[2]);
513
					$entry[2] = explode(' ', $entry[2]);
514
					$result['pause_out'] = $entry[2][0];
515
				} // if
516
			} elseif (mb_strpos($entry, 'output buffer failures') !== FALSE) {
517
				$entry = explode(',', $entry);
518
				$entry[0] = trim($entry[0]);
519
				$entry[0] = explode(' ', $entry[0]);
520
				$result['out_buffer_fail'] = $entry[0][0];
521
				$entry[1] = trim($entry[1]);
522
				$entry[1] = explode(' ', $entry[1]);
523
				$result['out_buffer_swap'] = $entry[1][0];
524
			} // if .. elseif
525
		} // foreach
526
		$this->_data = $result;
527
		return $this->_data;
528
	}
529
530
	/**
531
	 * @return array
532
	 */
533
	public function trunk_ports() {
534
		$result = [];
535
		$this->exec('show interface status | include trunk');
536
		$this->_data = explode("\r\n", $this->_data);
537
		array_shift($this->_data);
538
		array_pop($this->_data);
539
		if (count($this->_data) > 0) {
540
			foreach ($this->_data as $interface) {
541
				$interface = explode(' ', $interface);
542
				$result[] = $interface[0];
543
			} // foreach
544
		} // if
545
		$this->_data = $result;
546
		return $this->_data;
547
	}
548
549
	/**
550
	 * @return array
551
	 */
552
	public function vlans() {
553
		$result = [];
554
		$this->exec('show spanning-tree summary | include ^VLAN');
555
		$this->_data = explode("\r\n", $this->_data);
556
		array_shift($this->_data);
557
		array_pop($this->_data);
558
		if (count($this->_data) > 0) {
559
			foreach ($this->_data as $vlan) {
560
				$vlan = explode(' ', $vlan);
561
				$vlan = mb_substr($vlan[0], 4);
562
				$result[] = (int)$vlan;
563
			} // foreach
564
		} // if
565
		$this->_data = $result;
566
		return $this->_data;
567
	}
568
569
	/**
570
	 * @return array
571
	 */
572
	public function errdisabled() {
573
		$result = [];
574
		$this->exec('show int status err');
575
		$this->_data = explode("\r\n", $this->_data);
576
		for ($i = 0; $i < 2; $i++)
577
			array_shift($this->_data);
578
		array_pop($this->_data);
579
		$pos = mb_strpos($this->_data[0], 'Status');
580
		foreach ($this->_data as $entry) {
581
			$temp = trim($entry);
582
			if (mb_strlen($temp) > 1 && $temp[2] != 'r') {
583
				$entry = [];
584
				$entry['interface'] = mb_substr($temp, 0, mb_strpos($temp, ' '));
585
				$entry['description'] = trim(mb_substr($temp, mb_strpos($temp, ' ') + 1, $pos - mb_strlen($entry['interface']) - 1));
586
				$temp = mb_substr($temp, $pos);
587
				/** @noinspection PrintfScanfArgumentsInspection */
588
				$temp = sscanf($temp, '%s %s');
589
				$entry['status'] = $temp[0];
590
				$entry['reason'] = $temp[1];
591
				$result[] = $entry;
592
			} // if
593
		} // foreach
594
		$this->_data = $result;
595
		return $this->_data;
596
	}
597
598
	/**
599
	 * @return array
600
	 */
601
	public function dhcpsnoop_bindings() {
602
		$result = [];
603
		$this->exec('sh ip dhcp snoop binding | inc dhcp-snooping');
604
		$this->_data = explode("\r\n", $this->_data);
605
		array_shift($this->_data);
606
		array_pop($this->_data);
607
		foreach ($this->_data as $entry) {
608
			/** @noinspection PrintfScanfArgumentsInspection */
609
			$temp = sscanf($entry, '%s %s %s %s %s %s');
610
			$entry = [];
611
			$entry['mac_address'] = $temp[0];
612
			$entry['mac_address'] = strtolower(str_replace(':', '', $entry['mac_address']));
613
			$entry['ip_address'] = $temp[1];
614
			$entry['lease'] = $temp[2];
615
			$entry['vlan'] = $temp[4];
616
			$entry['interface'] = $temp[5];
617
			if ($temp[3] == 'dhcp-snooping')
618
				$result[] = $entry;
619
		}
620
		$this->_data = $result;
621
		return $this->_data;
622
	}
623
624
	/**
625
	 * @return array
626
	 */
627
	public function mac_address_table() {
628
		$result = [];
629
		$omit = $this->trunk_ports();
630
		$this->exec('show mac address-table | exclude CPU');
631
		$this->_data = str_replace('          ', '', $this->_data);
632
		$this->_data = explode("\r\n", $this->_data);
633
		for ($i = 0; $i < 6; $i++)
634
			array_shift($this->_data);
635
		for ($i = 0; $i < 2; $i++)
636
			array_pop($this->_data);
637
		foreach ($this->_data as $entry) {
638
			/** @noinspection PrintfScanfArgumentsInspection */
639
			$temp = sscanf($entry, '%s %s %s %s');
640
			$entry = [];
641
			$entry['mac_address'] = $temp[1];
642
			$entry['interface'] = $temp[3];
643
			if (in_array($entry['interface'], $omit) == FALSE) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
644
				$result[] = $entry;
645
			} // if
646
		} // foreach
647
		$this->_data = $result;
648
		return $this->_data;
649
	}
650
651
	/**
652
	 * @return array
653
	 */
654
	public function arp_table() {
655
		$result = [];
656
		$this->exec('show arp | exc Incomplete');
657
		$this->_data = explode("\r\n", $this->_data);
658
		for ($i = 0; $i < 2; $i++)
659
			array_shift($this->_data);
660
		array_pop($this->_data);
661
		foreach ($this->_data as $entry) {
662
			/** @noinspection PrintfScanfArgumentsInspection */
663
			$temp = sscanf($entry, '%s %s %s %s %s %s');
664
			$entry = [];
665
			$entry['ip'] = $temp[1];
666
			$entry['mac_address'] = $temp[3];
667
			if ($temp[2] == '-')
668
				$temp[2] = '0';
669
			$entry['age'] = $temp[2];
670
			$entry['interface'] = $temp[5];
671
			if ($entry['ip'] != 'Address' && $entry['mac_address'] != 'Incomplete') {
672
				$result[] = $entry;
673
			} // if
674
		} // foreach
675
		$this->_data = $result;
676
		return $this->_data;
677
	}
678
679
	/**
680
	 * @return array
681
	 */
682
	public function ipv6_neighbor_table() {
683
		$result = [];
684
		$this->exec('show ipv6 neighbors | exc INCMP');
685
		$this->_data = explode("\r\n", $this->_data);
686
		for ($i = 0; $i < 2; $i++)
687
			array_shift($this->_data);
688
		for ($i = 0; $i < 2; $i++)
689
			array_pop($this->_data);
690
		foreach ($this->_data as $entry) {
691
			/** @noinspection PrintfScanfArgumentsInspection */
692
			$temp = sscanf($entry, '%s %s %s %s %s');
693
			$entry = [];
694
			$entry['ipv6'] = $temp[0];
695
			$entry['mac_address'] = $temp[2];
696
			$entry['age'] = $temp[1];
697
			$entry['interface'] = $temp[4];
698
			$result[] = $entry;
699
		} // foreach
700
		$this->_data = $result;
701
		return $this->_data;
702
	}
703
704
	/**
705
	 * @return array
706
	 */
707
	public function ipv6_routers() {
708
		$result = [];
709
		$this->exec('show ipv6 routers');
710
		$this->_data = explode("\r\n", $this->_data);
711
		array_shift($this->_data);
712
		array_pop($this->_data);
713
		for ($i = 0, $iMax = count($this->_data); $i < $iMax; $i++) {
714
			$entry = trim($this->_data[$i]);
715
			if (mb_substr($entry, 0, 7) == 'Router ') {
716
				/** @noinspection PrintfScanfArgumentsInspection */
717
				$temp = sscanf($entry, '%s %s %s %s');
718
				$entry = [];
719
				$entry['router'] = $temp[1];
720
				$entry['interface'] = str_replace(',', '', $temp[3]);
721
				/** @noinspection PrintfScanfArgumentsInspection */
722
				$temp = sscanf(trim($this->_data[$i + 4]), '%s %s %s');
723
				$entry['prefix'] = $temp[1];
724
				$i += 5;
725
				$result[] = $entry;
726
			} // if
727
		} // for
728
		$this->_data = $result;
729
		return $this->_data;
730
	}
731
732
	/**
733
	 * @param $config
734
	 * @return null|boolean
735
	 */
736
	public function configure($config) {
737
		// USE AT OWN RISK: This function will apply configuration statements to a device.
738
		// Enabled Only
739
		if (mb_strpos($this->_prompt, '#') === FALSE)
740
			die('Error: User must be enabled to use configure()'.PHP_EOL);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
741
		$this->_data = explode("\n", $config);
742
		$this->_ssh->write("config t\n");
743
		$config_prompt = $this->_ssh->read('/.*[>|#]/', NET_SSH2_READ_REGEX);
0 ignored issues
show
Bug introduced by
The constant NET_SSH2_READ_REGEX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
744
		$config_prompt = str_replace("\r\n", '', trim($config_prompt));
745
		if (mb_strpos($config_prompt, 'config)#') !== FALSE) {
746
			foreach ($this->_data as $c)
747
				$this->_ssh->write($c . "\n");
748
			$this->_ssh->write("end\n");
749
		}
750
		$result = $this->_ssh->read($this->_prompt);
751
		$result = explode("\r\n", $result);
752
		if (count($this->_data) == (count($result) - 2))
753
			return TRUE;
754
		else
755
			die('Error: Switch rejected configuration: '.PHP_EOL . $config . "\n");
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
756
	}
757
758
	/**
759
	 * @return bool
760
	 */
761
	public function write_config() {
762
		$this->exec('write');
763
		if (mb_strpos($this->_data, '[OK]') !== FALSE)
764
			return TRUE; 
765
		else
766
			return FALSE;
767
	}
768
}
769
770
/**
771
 * Class cisco_parser
772
 */
773
class cisco_parser {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
774
	/**
775
	 * @param $lines
776
	 * @param integer $x
777
	 * @return int
778
	 */
779
	public function get_space_depth($lines, $x) {
780
		if (preg_match('/^(?P<spaces>\s+)*(?P<rest>\S.*)$/', $lines[$x], $matches)) {
781
			$cdepth = mb_strlen($matches['spaces']);
782
		} else {
783
			$cdepth = 0;
784
		}
785
		return $cdepth;
786
	}
787
788
	/**
789
	 * @param     $lines
790
	 * @param int $x
791
	 * @param int $depth
792
	 * @return array
793
	 */
794
	public function parse_cisco_children($lines, $x = 0, $depth = 0) {
795
		//global $x;
796
		$data = [];
797
		$last_command = FALSE;
0 ignored issues
show
Unused Code introduced by
The assignment to $last_command is dead and can be removed.
Loading history...
798
		for ($xMax = count($lines); $x < $xMax; $x++) {
799
			$cdepth = $this->get_space_depth($lines, $x);
800
			$command = ltrim($lines[$x]);
801
			$arguments = '';
802
			$spacepos = mb_strpos($command, ' ');
803
			if ($spacepos !== FALSE) {
804
				$arguments = mb_substr($command, $spacepos + 1);
805
				$command = mb_substr($command, 0, $spacepos);
806
				//echo "Got C|$command|A|$arguments|<br>";
807
			}
808
			if ($cdepth == $depth) {
809
				$new_data = ['command' => $command];
810
				if ($arguments != '')
811
					$new_data['arguments'] = trim($arguments);
812
				if ($x + 1 < count($lines)) {
813
					$next_depth = $this->get_space_depth($lines, $x + 1);
814
					if ($next_depth > $depth) {
815
						$new_data['children'] = $this->parse_cisco_children($lines, $x + 1, $next_depth);
816
						while ($this->get_space_depth($lines, $x + 1) > $depth)
817
							++$x;
818
					}
819
				}
820
				$data[] = $new_data;
821
			} elseif ($cdepth < $depth)
822
				return $data;
823
			else
824
				echo "SHOULD NEVER GET HERE\n";
825
		}
826
		return $data;
827
	}
828
}
829