使用 php Telnet 到 cisco 交换机
Posted
技术标签:
【中文标题】使用 php Telnet 到 cisco 交换机【英文标题】:Telnet to cisco switch using php 【发布时间】:2012-05-25 20:59:57 【问题描述】:我需要使用 php 远程登录到 cisco 交换机并执行 show interface status
命令并获得结果。我尝试了一些在互联网上找到的 php 类,但它们都无法连接到设备。所以我尝试自己编写脚本,但我遇到了同样的问题,我无法连接到设备。
主持人向我发送横幅消息,然后用username:
换行。
我用\r\n
发送我的用户名,等待一段时间并尝试读取数据,但在我看来主机只是忽略了我的换行符。这是我得到的回复(explode('\n') on response):
Array
(
[0] => %
[1] => User Access Verification
[2] => Username: timeout expired!
)
为什么没有提示输入密码?我尝试发送 telnet 标头,没有,没有变化。谁能帮帮我?
这是我的代码
<?
$host = "switchName";
$name = "name";
$pass = "pass";
$port = 23;
$timeOut = 15;
$connected = false;
$skipNullLines = true;
$timeout = 125000;
$header1=chr(0xFF).chr(0xFB).chr(0x1F).chr(0xFF).chr(0xFB).chr(0x20).chr(0xFF).chr(0xFB).chr(0x18).chr(0xFF).chr(0xFB).chr(0x27).chr(0xFF).chr(0xFD).chr(0x01).chr(0xFF).chr(0xFB).chr(0x03).chr(0xFF).chr(0xFD).chr(0x03).chr(0xFF).chr(0xFC).chr(0x23).chr(0xFF).chr(0xFC).chr(0x24).chr(0xFF).chr(0xFA).chr(0x1F).chr(0x00).chr(0x50).chr(0x00).chr(0x18).chr(0xFF).chr(0xF0).chr(0xFF).chr(0xFA).chr(0x20).chr(0x00).chr(0x33).chr(0x38).chr(0x34).chr(0x30).chr(0x30).chr(0x2C).chr(0x33).chr(0x38).chr(0x34).chr(0x30).chr(0x30).chr(0xFF).chr(0xF0).chr(0xFF).chr(0xFA).chr(0x27).chr(0x00).chr(0xFF).chr(0xF0).chr(0xFF).chr(0xFA).chr(0x18).chr(0x00).chr(0x41).chr(0x4E).chr(0x53).chr(0x49).chr(0xFF).chr(0xF0);
$header2=chr(0xFF).chr(0xFC).chr(0x01).chr(0xFF).chr(0xFC).chr(0x22).chr(0xFF).chr(0xFE).chr(0x05).chr(0xFF).chr(0xFC).chr(0x21);
function read_string()
global $fw,$host,$skipNullLines;
$string = "";
while( !feof($fw) )
$read = fgets($fw);
$string .= $read;
// Probably prompt, stop reading
if( strpos($read, ':') !== FALSE || strpos($read, '> (enable)') !== FALSE || strpos($read, $host.'#') !== FALSE)
break;
$string = explode("\n", $string);
// Get rid of null lines
$ret = array();
for($i = 0; $i<count($string); $i++)
if( trim($string[$i]) == '' && $skipNullLines ) continue;
$ret[] = $string[$i];
return $ret;
function send_string($string, $force=false)
GLOBAL $timeout,$fw;
$string = trim($string);
// execute only strings that are preceded by "show" (if not forced)
if(!$force && strpos($string, 'show ') !== 0)
return 1;
fputs($fw, $string."\r\n");
echo("SEND:".$string."\r\n");
usleep($timeout);
$fw = fsockopen($host, $port, $errno, $errorstr, $timeOut);
if($fw == false)
echo("Cant connect");
else
echo("Connected<br>");
$connected = true;
stream_set_timeout($fw, $timeout);
// fputs($fw, $header1);
// usleep($timeout);
// fputs($fw, $header2);
// usleep($timeout);
print_r(read_string());
send_string("test", true);
print_r(read_string());
fclose($fw);
?>
更新 如果我首先发送用户名,然后我阅读,我会收到密码提示。我不明白,为什么我不能先阅读主机的消息然后发送我的回复。现在它对我的工作方式(发送回复然后阅读提示)是没有意义的! (而且我仍然收到“% Authentication failed.” 正确密码/名称的消息事件)。
...
$connected = true;
stream_set_timeout($fw, $timeout);
send_string("name", true);
send_string("password", true);
print_r(read_string());
...
【问题讨论】:
【参考方案1】:好的,所以我不知道问题出在哪里,但是经过“几次”测试后,我能够编写适合我的这个类。我不知道为什么其他 telnet 类不工作,尽管它们几乎相同。所以如果有人有类似的问题,你可以试试这个:
class TELNET
private $host;
private $name;
private $pass;
private $port;
private $connected;
private $connect_timeout;
private $stream_timetout;
private $socket;
public function TELNET()
$this->port = 23;
$this->connected = false; // connected?
$this->connect_timeout = 10; // timeout while asking for connection
$this->stream_timeout = 380000; // timeout between I/O operations
public function __destruct()
if($this->connected) fclose($this->socket);
// Connects to host
// @$_host - addres (or hostname) of host
// @$_user - name of user to log in as
// $@_pass - password of user
//
// Return: TRUE on success, other way function will return error string got by fsockopen()
public function Connect($_host, $_user, $_pass)
// If connected successfully
if( ($this->socket = @fsockopen($_host, $this->port, $errno, $errorstr, $this->connect_timeout)) !== FALSE )
$this->host = $_host;
$this->user = $_user;
$this->pass = $_pass;
$this->connected = true;
stream_set_timeout($this->socket, 0, 380000);
stream_set_blocking($this->socket, 1);
return true;
// else if coulnt connect
else return $errorstr;
// LogIn to host
//
// RETURN: will return true on success, other way returns false
public function LogIn()
if(!$this->connected) return false;
// Send name and password
$this->SendString($this->user, true);
$this->SendString($this->pass, true);
// read answer
$data = $this->ReadTo(array('#'));
// did we get the prompt from host?
if( strtolower(trim($data[count($data)-1])) == strtolower($this->host).'#' ) return true;
else return false;
// Function will execute command on host and returns output
//
// @$_command - command to be executed, only commands beginning with "show " can be executed, you can change this by adding
// "true" (bool type) as the second argument for function SendString($command) inside this function (3rd line)
//
function GetOutputOf($_command)
if(!$this->connected) return false;
$this->SendString($_command);
$output = array();
$work = true;
//
// Read whole output
//
// read_to( array( STRINGS ) ), STRINGS are meant as possible endings of outputs
while( $work && $data = $this->ReadTo( array("--More--","#") ) )
// CHeck wheter we actually did read any data
$null_data = true;
foreach($data as $line)
if(trim($line) != "") $null_data = false;break;
if($null_data) break;
// if device is paging output, send space to get rest
if( trim($data[count($data)-1]) == '--More--')
// delete line with prompt (or "--More--")
unset($data[count($data)-1]);
// if second line is blank, delete it
if( trim($data[1]) == '' ) unset($data[1]);
// If first line contains send command, delete it
if( strpos($data[0], $_command)!==FALSE ) unset($data[0]);
// send space
fputs($this->socket, " ");
// ak ma vystup max dva riadky
// alebo sme uz nacitali prompt
// IF we got prompt (line ending with #)
// OR string that we've read has only one line
// THEN we reached end of data and stop reading
if( strpos($data[count($data)-1], '#')!==FALSE /* || (count($data) == 1 && $data[0] == "")*/ )
// delete line with prompt
unset($data[count($data)-1]);
// if second line is blank, delete it
if( trim($data[1]) == '' ) unset($data[1]);
// If first line contains send command, delete it
if( strpos($data[0], $_command)!==FALSE ) unset($data[0]);
// stop while cyclus
$work = false;
// get rid of empty lines at the end
for($i = count($data)-1; $i>0; $i--)
if(trim($data[$i]) == "") unset($data[$i]);
else break;
// add new data to $output
foreach($data as $v)
$output[] = $v;
// return output
return $output;
// Read from host until occurence of any index from $array_of_stops
// @array_of_stops - array that contains strings of texts that may be at the end of output
// RETURNS: output of command as array of lines
function ReadTo($array_of_stops)
$ret = array();
$max_empty_lines = 3;
$count_empty_lines = 0;
while( !feof($this->socket) )
$read = fgets($this->socket);
$ret[] = $read;
//
// Stop reading after (int)"$max_empty_lines" empty lines
//
if(trim($read) == "")
if($count_empty_lines++ > $max_empty_lines) break;
else $count_empty_lines = 0;
//
// Does last line of readed data contain any of "Stop" strings ??
$found = false;
foreach($array_of_stops AS $stop)
if( strpos($read, $stop) !== FALSE ) $found = true; break;
// If so, stop reading
if($found) break;
return $ret;
// Send string to host
// If force is set to false (default), function sends to host only strings that begins with "show "
//
// @$string - command to be executed
// @$force - force command? Execute if not preceeded by "show " ?
// @$newLine - append character of new line at the end of command?
function SendString($string, $force=false, $newLine=true)
$t1 = microtime(true);
$string = trim($string);
// execute only strings that are preceded by "show"
// and execute only one command (no new line characters) !
if(!$force && strpos($string, 'show ') !== 0 && count(explode("\n", $string)) == 1)
return 1;
if($newLine) $string .= "\n";
fputs($this->socket, $string);
$t2 = microtime(true);
// EXAMPLE
$host = "hostname";
$name = "username";
$pass = "password";
$t = new TELNET();
echo("CONNECT:".$t->Connect($host, $name, $pass)."<br>");
echo("LOGIN:".(int)$t->LogIn());
echo("<br>OUTPUT:<br>");
print_r($t->GetOutputOf("show snmp"));
print_r($t->GetOutputOf("show users"));
print_r($t->GetOutputOf("show interface status"));
PS:我的设备提示符是“主机名#”,因此您可能需要编辑登录功能以使此代码与您的设备提示符一起使用(因此您可能需要在 GetOutputOf() 中)
【讨论】:
以上是关于使用 php Telnet 到 cisco 交换机的主要内容,如果未能解决你的问题,请参考以下文章