Issues (12)

class.cisco.php (1 issue)

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;
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;
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));
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);
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);
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);
785
		}
786
		$this->_data = explode("\n", $config);
787
		$this->_ssh->write("config t\n");
788
		$config_prompt = $this->_ssh->read('/.*[>|#]/', NET_SSH2_READ_REGEX);
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");
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;
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