cisco::show_int()   F
last analyzed

Complexity

Conditions 26
Paths 26

Size

Total Lines 183
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 183
rs 3.3333

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

129
			$pos = !empty($match) ? mb_strpos($this->_response, /** @scrutinizer ignore-type */ $match) : false;
Loading history...
130
			//echo ++$i . "POS:".var_export($pos, TRUE).'<br>';
131
			if ($pos !== false) {
132
				//echo "$match Matching $pattern @ $pos <br>";
133
				return $this->_string_shift($this->_response, $pos + mb_strlen($match));
0 ignored issues
show
Bug introduced by
It seems like $match can also be of type array; however, parameter $string of mb_strlen() 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

133
				return $this->_string_shift($this->_response, $pos + mb_strlen(/** @scrutinizer ignore-type */ $match));
Loading history...
134
			}
135
			usleep(1000);
136
			$response = fgets($this->_stream);
137
			//echo "R$i:$response<br>";
138
			if (is_bool($response)) {
139
				//echo "Return B $response::".$this->_response."<br>";
140
				//					return $response ? $this->_string_shift($this->_response, mb_strlen($this->_response)) : false;
141
			}
142
			$this->_response .= $response;
143
		}
144
		echo 'FEOF !!!!<br>';
145
		return $this->_response;
146
	}
147
148
	/**
149
	 * @param string $cmd
150
	 */
151
	public function write($cmd)
152
	{
153
		fwrite($this->_stream, $cmd);
154
	}
155
156
	/**
157
	 * @return bool
158
	 */
159
	public function connect()
160
	{
161
		//echo "Connecting to " . $this->_hostname . "<br>";
162
		$this->_ssh = ssh2_connect($this->_hostname, $this->_port);
163
		if ($this->_ssh === false) {
164
			return false;
165
		}
166
		ssh2_auth_password($this->_ssh, $this->_username, $this->_password);
167
		$this->_stream = ssh2_shell($this->_ssh);
168
		$this->connected = true;
169
		$this->parse_motd_and_prompt();
170
		return true;
171
	}
172
173
	/**
174
	 *
175
	 */
176
	public function parse_motd_and_prompt()
177
	{
178
		$this->_motd = trim($this->read('/.*[>|#]/', true));
179
		$this->write("\n");
180
		$this->_prompt = trim($this->read('/.*[>|#]/', true));
181
		$length = mb_strlen($this->_prompt);
182
		if (mb_substr($this->_motd, -$length) == $this->_prompt) {
183
			$this->_motd = mb_substr($this->_motd, 0, -$length);
184
		}
185
		//echo "MOTD:".$this->_motd."<br>";
186
		//echo "Prompt:".$this->_prompt.'<br>';
187
		return true;
188
		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...
189
		$this->_motd = '';
190
		while ($this->_response = fgets($this->_stream)) {
191
			$this->_motd .= $this->_response;
192
		}
193
		$this->_motd = trim($this->_motd);
194
		fwrite($this->_stream, "\n");
195
		$this->_response = stream_get_contents($this->_stream);
196
		//stream_set_blocking($this->_stream, FALSE);
197
		$this->_prompt = trim($this->_response);
198
		/*			sleep (1);
199
		while ($this->_response = fgets($this->_stream))
200
			$this->_prompt .= $this->_response;
201
		$this->_prompt = trim($this->_prompt);*/
202
		echo 'MOTD:'.$this->_motd.'<br>';
203
		echo 'Prompt:'.$this->_prompt.'<br>';
204
		$length = mb_strlen($this->_prompt);
205
		if (mb_substr($this->_motd, -$length) == $this->_prompt) {
206
			//echo "Found Prompt<br>";
207
			$this->_motd = mb_substr($this->_motd, 0, -$length);
208
		}
209
		//echo "MOTD:".$this->_motd . "<br>";
210
		echo 'Prompt:'.$this->_prompt.'<br>';
211
		/*			$this->_stream = ssh2_exec($this->_ssh, "#");
212
		stream_set_blocking($this->_stream, TRUE);
213
		$this->_response = stream_get_contents($this->_stream);
214
		$this->_data = $this->_response;
215
		stream_set_blocking($this->_stream, FALSE);
216
		var_dump($this->_response);
217
		*/
218
	}
219
220
	/**
221
	 * @param string $cmd
222
	 * @return string
223
	 */
224
	public function exec($cmd)
225
	{
226
		if ($this->autoconnect === true && $this->connected === false) {
227
			$this->connect();
228
		}
229
		if (mb_substr($cmd, -1) != "\n") {
230
			//error_log("Adding NEWLINE Character To SSH2 Command $cmd", __LINE__, __FILE__);
231
			$cmd .= "\n";
232
		}
233
		$this->_data = false;
234
		fwrite($this->_stream, $cmd);
235
		$this->_response = trim($this->read($this->_prompt));
236
		$length = mb_strlen($this->_prompt);
237
		if (mb_substr($this->_response, -$length) == $this->_prompt) {
238
			//echo "Found Prompt<br>";
239
			$this->_response = mb_substr($this->_response, 0, -$length);
240
		}
241
		$this->_data = $this->_response;
242
		//stream_set_blocking($this->_stream, FALSE);
243
		//if (mb_strpos($this->_data, '% Invalid input detected') !== FALSE) $this->_data = FALSE;
244
		return $this->_data;
245
	}
246
247
	/**
248
	 * @return string
249
	 */
250
	public function get_response()
251
	{
252
		return $this->_response;
253
	}
254
255
	/**
256
	 *
257
	 */
258
	public function disconnect()
259
	{
260
		//ssh2_exec($this->_ssh, 'quit');
261
		$this->connected = false;
262
	}
263
264
	/**
265
	 *
266
	 */
267
	public function __destruct()
268
	{
269
		if ($this->connected === true) {
270
			$this->disconnect();
271
		}
272
	}
273
274
	/**
275
	 * @param $int
276
	 * @return string
277
	 */
278
	public function show_int_config($int)
279
	{
280
		// Enabled Only
281
		//if (mb_strpos($this->_prompt, '#') === FALSE)
282
		//	die('Error: User must be enabled to use show_int_config()'.PHP_EOL);
283
		$this->exec('show run int '.$int);
284
		return $this->show_int_config_parser();
285
	}
286
287
	/**
288
	 * @return string
289
	 */
290
	public function show_int_config_parser()
291
	{
292
		$this->_data = explode("\r\n", $this->_data);
293
		for ($i = 0; $i < 5; $i++) {
294
			array_shift($this->_data);
295
		}
296
		for ($i = 0; $i < 2; $i++) {
297
			array_pop($this->_data);
298
		}
299
		$this->_data = implode("\n", $this->_data);
300
		return $this->_data;
301
	}
302
303
	/**
304
	 * @return array
305
	 */
306
	public function show_int_status()
307
	{
308
		$result = [];
309
		$this->exec('show int status');
310
		$this->_data = explode("\r\n", $this->_data);
311
		for ($i = 0; $i < 2; $i++) {
312
			array_shift($this->_data);
313
		}
314
		array_pop($this->_data);
315
		$pos = mb_strpos($this->_data[0], 'Status');
316
		foreach ($this->_data as $entry) {
317
			$temp = trim($entry);
318
			if (mb_strlen($temp) > 1 && $temp[2] != 'r' && $temp[0] != '-') {
319
				$entry = [];
320
				$entry['interface'] = mb_substr($temp, 0, mb_strpos($temp, ' '));
321
				$entry['description'] = trim(mb_substr($temp, mb_strpos($temp, ' ') + 1, $pos - mb_strlen($entry['interface']) - 1));
322
				$temp = mb_substr($temp, $pos);
323
				/** @noinspection PrintfScanfArgumentsInspection */
324
				$temp = sscanf($temp, '%s %s %s %s %s %s');
325
				$entry['status'] = $temp[0];
326
				$entry['vlan'] = $temp[1];
327
				$entry['duplex'] = $temp[2];
328
				$entry['speed'] = $temp[3];
329
				$entry['type'] = trim($temp[4].' '.$temp[5]);
330
				$result[] = $entry;
331
			} // if
332
		} // foreach
333
		$this->_data = $result;
334
		return $this->_data;
335
	}
336
337
	/**
338
	 * @return array
339
	 */
340
	public function show_log()
341
	{
342
		// Enabled Only
343
		if (mb_strpos($this->_prompt, '#') === false) {
344
			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...
345
		}
346
		$result = [];
347
		$this->exec('sh log | inc %');
348
		$this->_data = explode("\r\n", $this->_data);
349
		array_shift($this->_data);
350
		array_pop($this->_data);
351
		foreach ($this->_data as $entry) {
352
			$temp = trim($entry);
353
			$entry = [];
354
			$entry['timestamp'] = mb_substr($temp, 0, mb_strpos($temp, '%') - 2);
355
			if ($entry['timestamp'][0] == '.' || $entry['timestamp'][0] == '*') {
356
				$entry['timestamp'] = mb_substr($entry['timestamp'], 1);
357
			}
358
			$temp = mb_substr($temp, mb_strpos($temp, '%') + 1);
359
			$entry['type'] = mb_substr($temp, 0, mb_strpos($temp, ':'));
360
			$temp = mb_substr($temp, mb_strpos($temp, ':') + 2);
361
			$entry['message'] = $temp;
362
			$result[] = $entry;
363
		} // foreach
364
		$this->_data = $result;
365
		return $this->_data;
366
	}
367
368
	/**
369
	 * @param $int
370
	 * @return array
371
	 */
372
	public function show_int($int)
373
	{
374
		$result = [];
375
		$this->exec('show int '.$int);
376
		$this->_data = explode("\r\n", $this->_data);
377
		foreach ($this->_data as $entry) {
378
			$entry = trim($entry);
379
			if (mb_strpos($entry, 'line protocol') !== false) {
380
				$result['interface'] = mb_substr($entry, 0, mb_strpos($entry, ' '));
381
				if (mb_strpos($entry, 'administratively') !== false) {
382
					$result['status'] = 'disabled';
383
				} elseif (mb_substr($entry, mb_strpos($entry, 'line protocol') + 17, 2) == 'up') {
384
					$result['status'] = 'connected';
385
				} else {
386
					$result['status'] = 'notconnect';
387
				} // if .. else
388
			} elseif (mb_strpos($entry, 'Description: ') !== false) {
389
				$entry = explode(':', $entry);
390
				$result['description'] = trim($entry[1]);
391
			} elseif (mb_strpos($entry, 'MTU') !== false) {
392
				$entry = explode(',', $entry);
393
				$entry[0] = trim($entry[0]);
394
				$entry[0] = explode(' ', $entry[0]);
395
				$result['mtu'] = $entry[0][1];
396
				$entry[1] = trim($entry[1]);
397
				$entry[1] = explode(' ', $entry[1]);
398
				$result['bandwidth'] = $entry[1][1];
399
				$entry[2] = trim($entry[2]);
400
				$entry[2] = explode(' ', $entry[2]);
401
				$result['dly'] = $entry[2][1];
402
			} elseif (mb_strpos($entry, 'duplex') !== false) {
403
				$entry = explode(',', $entry);
404
				$entry[0] = trim($entry[0]);
405
				$entry[0] = explode(' ', $entry[0]);
406
				$entry[0][0] = explode('-', $entry[0][0]);
407
				$result['duplex'] = strtolower($entry[0][0][0]);
408
				$entry[1] = trim($entry[1]);
409
				if (mb_strpos($entry[1], 'Auto') !== false) {
410
					$result['speed'] = 'auto';
411
				} else {
412
					$result['speed'] = (int) $entry[1];
413
				} // if .. else
414
				$entry[2] = rtrim($entry[2]);
415
				$result['type'] = mb_substr($entry[2], mb_strrpos($entry[2], ' ') + 1);
416
			} elseif (mb_strpos($entry, 'input rate') !== false) {
417
				$entry = explode(',', $entry);
418
				$result['in_rate'] = mb_substr($entry[0], mb_strpos($entry[0], 'rate') + 5, mb_strrpos($entry[0], ' ') - (mb_strpos($entry[0], 'rate') + 5));
419
				$entry = trim($entry[1]);
420
				$entry = explode(' ', $entry);
421
				$result['in_packet_rate'] = $entry[0];
422
			} elseif (mb_strpos($entry, 'output rate') !== false) {
423
				$entry = explode(',', $entry);
424
				$result['out_rate'] = mb_substr($entry[0], mb_strpos($entry[0], 'rate') + 5, mb_strrpos($entry[0], ' ') - (mb_strpos($entry[0], 'rate') + 5));
425
				$entry = trim($entry[1]);
426
				$entry = explode(' ', $entry);
427
				$result['out_packet_rate'] = $entry[0];
428
			} elseif (mb_strpos($entry, 'packets input') !== false) {
429
				$entry = explode(',', $entry);
430
				$entry[0] = trim($entry[0]);
431
				$entry[0] = explode(' ', $entry[0]);
432
				$result['in_packet'] = $entry[0][0];
433
				$entry[1] = trim($entry[1]);
434
				$entry[1] = explode(' ', $entry[1]);
435
				$result['in'] = $entry[1][0];
436
				if (count($entry) > 2) {
437
					$entry[2] = trim($entry[2]);
438
					$entry[2] = explode(' ', $entry[2]);
439
					$result['no_buffer'] = $entry[2][0];
440
				} // if
441
			} elseif (mb_strpos($entry, 'Received') !== false) {
442
				$entry = explode(',', $entry);
443
				$entry[0] = trim($entry[0]);
444
				$entry[0] = explode(' ', $entry[0]);
445
				$result['broadcast'] = $entry[0][1];
446
				if (count($entry) > 1) {
447
					$entry[1] = trim($entry[1]);
448
					$entry[1] = explode(' ', $entry[1]);
449
					$result['runt'] = $entry[1][0];
450
					$entry[2] = trim($entry[2]);
451
					$entry[2] = explode(' ', $entry[2]);
452
					$result['giant'] = $entry[2][0];
453
					$entry[3] = trim($entry[3]);
454
					$entry[3] = explode(' ', $entry[3]);
455
					$result['throttle'] = $entry[3][0];
456
				} // if
457
			} elseif (mb_strpos($entry, 'CRC') !== false) {
458
				$entry = explode(',', $entry);
459
				$entry[0] = trim($entry[0]);
460
				$entry[0] = explode(' ', $entry[0]);
461
				$result['in_error'] = $entry[0][0];
462
				$entry[1] = trim($entry[1]);
463
				$entry[1] = explode(' ', $entry[1]);
464
				$result['crc'] = $entry[1][0];
465
				$entry[2] = trim($entry[2]);
466
				$entry[2] = explode(' ', $entry[2]);
467
				$result['frame'] = $entry[2][0];
468
				$entry[3] = trim($entry[3]);
469
				$entry[3] = explode(' ', $entry[3]);
470
				$result['overrun'] = $entry[3][0];
471
				$entry[4] = trim($entry[4]);
472
				$entry[4] = explode(' ', $entry[4]);
473
				$result['ignored'] = $entry[4][0];
474
			} elseif (mb_strpos($entry, 'watchdog') !== false) {
475
				$entry = explode(',', $entry);
476
				$entry[0] = trim($entry[0]);
477
				$entry[0] = explode(' ', $entry[0]);
478
				$result['watchdog'] = $entry[0][0];
479
				$entry[1] = trim($entry[1]);
480
				$entry[1] = explode(' ', $entry[1]);
481
				$result['multicast'] = $entry[1][0];
482
				if (count($entry) > 2) {
483
					$entry[2] = trim($entry[2]);
484
					$entry[2] = explode(' ', $entry[2]);
485
					$result['pause_in'] = $entry[2][0];
486
				} // if
487
			} elseif (mb_strpos($entry, 'dribble') !== false) {
488
				$entry = trim($entry);
489
				$entry = explode(' ', $entry);
490
				$result['in_dribble'] = $entry[0];
491
			} elseif (mb_strpos($entry, 'packets output') !== false) {
492
				$entry = explode(',', $entry);
493
				$entry[0] = trim($entry[0]);
494
				$entry[0] = explode(' ', $entry[0]);
495
				$result['out_packet'] = $entry[0][0];
496
				$entry[1] = trim($entry[1]);
497
				$entry[1] = explode(' ', $entry[1]);
498
				$result['out'] = $entry[1][0];
499
				$entry[2] = trim($entry[2]);
500
				$entry[2] = explode(' ', $entry[2]);
501
				$result['underrun'] = $entry[2][0];
502
			} elseif (mb_strpos($entry, 'output errors') !== false) {
503
				$entry = explode(',', $entry);
504
				$entry[0] = trim($entry[0]);
505
				$entry[0] = explode(' ', $entry[0]);
506
				$result['out_error'] = $entry[0][0];
507
				if (count($entry) > 2) {
508
					$entry[1] = trim($entry[1]);
509
					$entry[1] = explode(' ', $entry[1]);
510
					$result['collision'] = $entry[1][0];
511
					$entry[2] = trim($entry[2]);
512
					$entry[2] = explode(' ', $entry[2]);
513
					$result['reset'] = $entry[2][0];
514
				} else {
515
					$entry[1] = trim($entry[1]);
516
					$entry[1] = explode(' ', $entry[1]);
517
					$result['reset'] = $entry[1][0];
518
				} // if .. else
519
			} elseif (mb_strpos($entry, 'babbles') !== false) {
520
				$entry = explode(',', $entry);
521
				$entry[0] = trim($entry[0]);
522
				$entry[0] = explode(' ', $entry[0]);
523
				$result['babble'] = $entry[0][0];
524
				$entry[1] = trim($entry[1]);
525
				$entry[1] = explode(' ', $entry[1]);
526
				$result['late_collision'] = $entry[1][0];
527
				$entry[2] = trim($entry[2]);
528
				$entry[2] = explode(' ', $entry[2]);
529
				$result['deferred'] = $entry[2][0];
530
			} elseif (mb_strpos($entry, 'lost carrier') !== false) {
531
				$entry = explode(',', $entry);
532
				$entry[0] = trim($entry[0]);
533
				$entry[0] = explode(' ', $entry[0]);
534
				$result['lost_carrier'] = $entry[0][0];
535
				$entry[1] = trim($entry[1]);
536
				$entry[1] = explode(' ', $entry[1]);
537
				$result['no_carrier'] = $entry[1][0];
538
				if (count($entry) > 2) {
539
					$entry[2] = trim($entry[2]);
540
					$entry[2] = explode(' ', $entry[2]);
541
					$result['pause_out'] = $entry[2][0];
542
				} // if
543
			} elseif (mb_strpos($entry, 'output buffer failures') !== false) {
544
				$entry = explode(',', $entry);
545
				$entry[0] = trim($entry[0]);
546
				$entry[0] = explode(' ', $entry[0]);
547
				$result['out_buffer_fail'] = $entry[0][0];
548
				$entry[1] = trim($entry[1]);
549
				$entry[1] = explode(' ', $entry[1]);
550
				$result['out_buffer_swap'] = $entry[1][0];
551
			} // if .. elseif
552
		} // foreach
553
		$this->_data = $result;
554
		return $this->_data;
555
	}
556
557
	/**
558
	 * @return array
559
	 */
560
	public function trunk_ports()
561
	{
562
		$result = [];
563
		$this->exec('show interface status | include trunk');
564
		$this->_data = explode("\r\n", $this->_data);
565
		array_shift($this->_data);
566
		array_pop($this->_data);
567
		if (count($this->_data) > 0) {
568
			foreach ($this->_data as $interface) {
569
				$interface = explode(' ', $interface);
570
				$result[] = $interface[0];
571
			} // foreach
572
		} // if
573
		$this->_data = $result;
574
		return $this->_data;
575
	}
576
577
	/**
578
	 * @return array
579
	 */
580
	public function vlans()
581
	{
582
		$result = [];
583
		$this->exec('show spanning-tree summary | include ^VLAN');
584
		$this->_data = explode("\r\n", $this->_data);
585
		array_shift($this->_data);
586
		array_pop($this->_data);
587
		if (count($this->_data) > 0) {
588
			foreach ($this->_data as $vlan) {
589
				$vlan = explode(' ', $vlan);
590
				$vlan = mb_substr($vlan[0], 4);
591
				$result[] = (int) $vlan;
592
			} // foreach
593
		} // if
594
		$this->_data = $result;
595
		return $this->_data;
596
	}
597
598
	/**
599
	 * @return array
600
	 */
601
	public function errdisabled()
602
	{
603
		$result = [];
604
		$this->exec('show int status err');
605
		$this->_data = explode("\r\n", $this->_data);
606
		for ($i = 0; $i < 2; $i++) {
607
			array_shift($this->_data);
608
		}
609
		array_pop($this->_data);
610
		$pos = mb_strpos($this->_data[0], 'Status');
611
		foreach ($this->_data as $entry) {
612
			$temp = trim($entry);
613
			if (mb_strlen($temp) > 1 && $temp[2] != 'r') {
614
				$entry = [];
615
				$entry['interface'] = mb_substr($temp, 0, mb_strpos($temp, ' '));
616
				$entry['description'] = trim(mb_substr($temp, mb_strpos($temp, ' ') + 1, $pos - mb_strlen($entry['interface']) - 1));
617
				$temp = mb_substr($temp, $pos);
618
				/** @noinspection PrintfScanfArgumentsInspection */
619
				$temp = sscanf($temp, '%s %s');
620
				$entry['status'] = $temp[0];
621
				$entry['reason'] = $temp[1];
622
				$result[] = $entry;
623
			} // if
624
		} // foreach
625
		$this->_data = $result;
626
		return $this->_data;
627
	}
628
629
	/**
630
	 * @return array
631
	 */
632
	public function dhcpsnoop_bindings()
633
	{
634
		$result = [];
635
		$this->exec('sh ip dhcp snoop binding | inc dhcp-snooping');
636
		$this->_data = explode("\r\n", $this->_data);
637
		array_shift($this->_data);
638
		array_pop($this->_data);
639
		foreach ($this->_data as $entry) {
640
			/** @noinspection PrintfScanfArgumentsInspection */
641
			$temp = sscanf($entry, '%s %s %s %s %s %s');
642
			$entry = [];
643
			$entry['mac_address'] = $temp[0];
644
			$entry['mac_address'] = strtolower(str_replace(':', '', $entry['mac_address']));
645
			$entry['ip_address'] = $temp[1];
646
			$entry['lease'] = $temp[2];
647
			$entry['vlan'] = $temp[4];
648
			$entry['interface'] = $temp[5];
649
			if ($temp[3] == 'dhcp-snooping') {
650
				$result[] = $entry;
651
			}
652
		}
653
		$this->_data = $result;
654
		return $this->_data;
655
	}
656
657
	/**
658
	 * @return array
659
	 */
660
	public function mac_address_table()
661
	{
662
		$result = [];
663
		$omit = $this->trunk_ports();
664
		$this->exec('show mac address-table | exclude CPU');
665
		$this->_data = str_replace('          ', '', $this->_data);
666
		$this->_data = explode("\r\n", $this->_data);
667
		for ($i = 0; $i < 6; $i++) {
668
			array_shift($this->_data);
669
		}
670
		for ($i = 0; $i < 2; $i++) {
671
			array_pop($this->_data);
672
		}
673
		foreach ($this->_data as $entry) {
674
			/** @noinspection PrintfScanfArgumentsInspection */
675
			$temp = sscanf($entry, '%s %s %s %s');
676
			$entry = [];
677
			$entry['mac_address'] = $temp[1];
678
			$entry['interface'] = $temp[3];
679
			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...
680
				$result[] = $entry;
681
			} // if
682
		} // foreach
683
		$this->_data = $result;
684
		return $this->_data;
685
	}
686
687
	/**
688
	 * @return array
689
	 */
690
	public function arp_table()
691
	{
692
		$result = [];
693
		$this->exec('show arp | exc Incomplete');
694
		$this->_data = explode("\r\n", $this->_data);
695
		for ($i = 0; $i < 2; $i++) {
696
			array_shift($this->_data);
697
		}
698
		array_pop($this->_data);
699
		foreach ($this->_data as $entry) {
700
			/** @noinspection PrintfScanfArgumentsInspection */
701
			$temp = sscanf($entry, '%s %s %s %s %s %s');
702
			$entry = [];
703
			$entry['ip'] = $temp[1];
704
			$entry['mac_address'] = $temp[3];
705
			if ($temp[2] == '-') {
706
				$temp[2] = '0';
707
			}
708
			$entry['age'] = $temp[2];
709
			$entry['interface'] = $temp[5];
710
			if ($entry['ip'] != 'Address' && $entry['mac_address'] != 'Incomplete') {
711
				$result[] = $entry;
712
			} // if
713
		} // foreach
714
		$this->_data = $result;
715
		return $this->_data;
716
	}
717
718
	/**
719
	 * @return array
720
	 */
721
	public function ipv6_neighbor_table()
722
	{
723
		$result = [];
724
		$this->exec('show ipv6 neighbors | exc INCMP');
725
		$this->_data = explode("\r\n", $this->_data);
726
		for ($i = 0; $i < 2; $i++) {
727
			array_shift($this->_data);
728
		}
729
		for ($i = 0; $i < 2; $i++) {
730
			array_pop($this->_data);
731
		}
732
		foreach ($this->_data as $entry) {
733
			/** @noinspection PrintfScanfArgumentsInspection */
734
			$temp = sscanf($entry, '%s %s %s %s %s');
735
			$entry = [];
736
			$entry['ipv6'] = $temp[0];
737
			$entry['mac_address'] = $temp[2];
738
			$entry['age'] = $temp[1];
739
			$entry['interface'] = $temp[4];
740
			$result[] = $entry;
741
		} // foreach
742
		$this->_data = $result;
743
		return $this->_data;
744
	}
745
746
	/**
747
	 * @return array
748
	 */
749
	public function ipv6_routers()
750
	{
751
		$result = [];
752
		$this->exec('show ipv6 routers');
753
		$this->_data = explode("\r\n", $this->_data);
754
		array_shift($this->_data);
755
		array_pop($this->_data);
756
		for ($i = 0, $iMax = count($this->_data); $i < $iMax; $i++) {
757
			$entry = trim($this->_data[$i]);
758
			if (mb_substr($entry, 0, 7) == 'Router ') {
759
				/** @noinspection PrintfScanfArgumentsInspection */
760
				$temp = sscanf($entry, '%s %s %s %s');
761
				$entry = [];
762
				$entry['router'] = $temp[1];
763
				$entry['interface'] = str_replace(',', '', $temp[3]);
764
				/** @noinspection PrintfScanfArgumentsInspection */
765
				$temp = sscanf(trim($this->_data[$i + 4]), '%s %s %s');
766
				$entry['prefix'] = $temp[1];
767
				$i += 5;
768
				$result[] = $entry;
769
			} // if
770
		} // for
771
		$this->_data = $result;
772
		return $this->_data;
773
	}
774
775
	/**
776
	 * @param $config
777
	 * @return null|boolean
778
	 */
779
	public function configure($config)
780
	{
781
		// USE AT OWN RISK: This function will apply configuration statements to a device.
782
		// Enabled Only
783
		if (mb_strpos($this->_prompt, '#') === false) {
784
			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...
785
		}
786
		$this->_data = explode("\n", $config);
787
		$this->_ssh->write("config t\n");
788
		$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...
789
		$config_prompt = str_replace("\r\n", '', trim($config_prompt));
790
		if (mb_strpos($config_prompt, 'config)#') !== false) {
791
			foreach ($this->_data as $c) {
792
				$this->_ssh->write($c."\n");
793
			}
794
			$this->_ssh->write("end\n");
795
		}
796
		$result = $this->_ssh->read($this->_prompt);
797
		$result = explode("\r\n", $result);
798
		if (count($this->_data) == (count($result) - 2)) {
799
			return true;
800
		} else {
801
			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...
802
		}
803
	}
804
805
	/**
806
	 * @return bool
807
	 */
808
	public function write_config()
809
	{
810
		$this->exec('write');
811
		if (mb_strpos($this->_data, '[OK]') !== false) {
812
			return true;
813
		} else {
814
			return false;
815
		}
816
	}
817
}
818
819
/**
820
 * Class cisco_parser
821
 */
822
class cisco_parser
823
{
824
	/**
825
	 * @param $lines
826
	 * @param integer $x
827
	 * @return int
828
	 */
829
	public function get_space_depth($lines, $x)
830
	{
831
		if (preg_match('/^(?P<spaces>\s+)*(?P<rest>\S.*)$/', $lines[$x], $matches)) {
832
			$cdepth = mb_strlen($matches['spaces']);
833
		} else {
834
			$cdepth = 0;
835
		}
836
		return $cdepth;
837
	}
838
839
	/**
840
	 * @param     $lines
841
	 * @param int $x
842
	 * @param int $depth
843
	 * @return array
844
	 */
845
	public function parse_cisco_children($lines, $x = 0, $depth = 0)
846
	{
847
		//global $x;
848
		$data = [];
849
		$last_command = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $last_command is dead and can be removed.
Loading history...
850
		for ($xMax = count($lines); $x < $xMax; $x++) {
851
			$cdepth = $this->get_space_depth($lines, $x);
852
			$command = ltrim($lines[$x]);
853
			$arguments = '';
854
			$spacepos = mb_strpos($command, ' ');
855
			if ($spacepos !== false) {
856
				$arguments = mb_substr($command, $spacepos + 1);
857
				$command = mb_substr($command, 0, $spacepos);
858
				//echo "Got C|$command|A|$arguments|<br>";
859
			}
860
			if ($cdepth == $depth) {
861
				$new_data = ['command' => $command];
862
				if ($arguments != '') {
863
					$new_data['arguments'] = trim($arguments);
864
				}
865
				if ($x + 1 < count($lines)) {
866
					$next_depth = $this->get_space_depth($lines, $x + 1);
867
					if ($next_depth > $depth) {
868
						$new_data['children'] = $this->parse_cisco_children($lines, $x + 1, $next_depth);
869
						while ($this->get_space_depth($lines, $x + 1) > $depth) {
870
							++$x;
871
						}
872
					}
873
				}
874
				$data[] = $new_data;
875
			} elseif ($cdepth < $depth) {
876
				return $data;
877
			} else {
878
				echo "SHOULD NEVER GET HERE\n";
879
			}
880
		}
881
		return $data;
882
	}
883
}
884