host = $host;
$this->port = $port;
$this->timeout = $timeout;
$this->setStreamTimeout($stream_timeout);
// set some telnet special characters
$this->NULL = chr(0);
$this->DC1 = chr(17);
$this->WILL = chr(251);
$this->WONT = chr(252);
$this->DO = chr(253);
$this->DONT = chr(254);
$this->IAC = chr(255);
$this->connect();
}
/**
* Destructor. Cleans up socket connection and command buffer
*
* @return
* @throws \Exception
*/
public function __destruct() {
// clean up resources
$this->disconnect();
$this->buffer = NULL;
$this->global_buffer = NULL;
}
/**
* Attempts connection to remote host. Returns TRUE if successful.
*
* @return boolean
* @throws \Exception
*/
public function connect()
{
// check if we need to convert host to IP
if (!preg_match('/([0-9]{1,3}\\.){3,3}[0-9]{1,3}/', $this->host)) {
$ip = gethostbyname($this->host);
if ($this->host == $ip) {
throw new \Exception("Cannot resolve $this->host");
} else {
$this->host = $ip;
}
}
// attempt connection - suppress warnings
$this->socket = @fsockopen($this->host, $this->port, $this->errno, $this->errstr, $this->timeout);
if (!$this->socket) {
throw new \Exception("Cannot connect to $this->host on port $this->port");
}
return self::TELNET_OK;
}
/**
* Closes IP socket
*
* @return boolean
* @throws \Exception
*/
public function disconnect()
{
if ($this->socket) {
if (! fclose($this->socket)) {
throw new \Exception("Error while closing telnet socket");
}
$this->socket = NULL;
}
return self::TELNET_OK;
}
/**
* Executes command and returns a string with result.
* This method is a wrapper for lower level private methods
*
* @param string $command Command to execute
* @param boolean $add_newline Default TRUE, adds newline to the command
* @return string Command result
* @throws \Exception
*/
public function exec($command, $add_newline = true)
{
$this->write($command, $add_newline);
$this->waitPrompt();
return $this->getBuffer();
}
/**
* Attempts login to remote host.
* This method is a wrapper for lower level private methods and should be
* modified to reflect telnet implementation details like login/password
* and line prompts. Defaults to standard unix non-root prompts
*
* @param string $username Username
* @param string $password Password
* @throws \Exception
* @return boolean
*/
public function login($username, $password)
{
try {
$this->waitPrompt();
$this->write($username);
$this->waitPrompt();
$this->write($password);
$this->waitPrompt();
} catch (\Exception $e) {
throw new \Exception("Login failed: ".$e->getMessage());
}
return self::TELNET_OK;
}
/**
* Sets the stream timeout.
*
* @param float $timeout
* @return void
*/
public function setStreamTimeout($timeout)
{
$this->stream_timeout_usec = (int)(fmod($timeout, 1) * 1000000);
$this->stream_timeout_sec = (int)$timeout;
}
/**s
* Gets character from the socket
*/
protected function getc()
{
stream_set_timeout($this->socket, $this->stream_timeout_sec, $this->stream_timeout_usec);
$c = fgetc($this->socket);
$this->global_buffer .= $c;
return $c;
}
/**
* Clears internal command buffer
*
* @return void
*/
public function clearBuffer()
{
$this->buffer = '';
}
/**
* Reads characters from the socket and adds them to command buffer.
* Handles telnet control characters. Stops when prompt is ecountered.
*
* @param string $prompt
* @return boolean
* @throws \Exception
*/
protected function readTo($prompt)
{
if (!$this->socket) throw new \Exception("Telnet connection closed");
$this->clearBuffer();
$until_t = time() + $this->timeout;
do {
// time's up (loop can be exited at end or through continue!)
if (time() > $until_t) {
throw new \Exception("Couldn't find the requested : '$prompt' within {$this->timeout} seconds");
}
$c = $this->getc();
if ($c === false) {
if (empty($prompt)) return self::TELNET_OK;
throw new \Exception("Couldn't find the requested : '" . $prompt . "', it was not in the data returned from server: " . $this->buffer);
}
// Interpreted As Command
if ($c == $this->IAC) {
if ($this->negotiateTelnetOptions()) {
continue;
}
}
// append current char to global buffer
$this->buffer .= $c;
} while ($c != $this->NULL || $c != $this->DC1);
}
/**
* Write command to a socket
*
* @param string $buffer Stuff to write to socket
* @param boolean $newline Default TRUE, adds newline to the command
* @return boolean
* @throws \Exception
*/
protected function write($buffer, $newline = true)
{
if (!$this->socket) throw new \Exception("Telnet connection closed");
// clear buffer from last command
$this->clearBuffer();
if ($newline) $buffer .= "\n";
$this->global_buffer .= $buffer;
if (!fwrite($this->socket, $buffer) < 0) throw new \Exception("Error writing to socket");
return self::TELNET_OK;
}
/**
* Returns the content of the command buffer
*
* @return string Content of the command buffer
*/
protected function getBuffer()
{
// Remove all carriage returns from line breaks
$buf = preg_replace('/\r\n|\r/', "\n", $this->buffer);
// Cut last line from buffer (almost always prompt)
if ($this->strip_prompt) {
$buf = explode("\n", $buf);
unset($buf[count($buf) - 1]);
$buf = implode("\n", $buf);
}
return trim($buf);
}
/**
* Returns the content of the global command buffer
*
* @return string Content of the global command buffer
*/
public function getGlobalBuffer()
{
return $this->global_buffer;
}
/**
* Telnet control character magic
*
* @return boolean
* @throws \Exception
*/
protected function negotiateTelnetOptions()
{
$c = $this->getc();
if ($c != $this->IAC) {
if (($c == $this->DO) || ($c == $this->DONT)) {
$opt = $this->getc();
fwrite($this->socket, $this->IAC . $this->WONT . $opt);
} else if (($c == $this->WILL) || ($c == $this->WONT)) {
$opt = $this->getc();
fwrite($this->socket, $this->IAC . $this->DONT . $opt);
} else {
throw new \Exception('Error: unknown control character ' . ord($c));
}
} else {
throw new \Exception('Error: Something Wicked Happened');
}
return self::TELNET_OK;
}
/**
* Reads socket until prompt is encountered
* @return boolean
* @throws \Exception
*/
protected function waitPrompt()
{
return $this->readTo('');
}
}
使用案例
$telnet = new Telnet($this->host, $this->port, 10);
$telnet->login($this->username, $this->password);
$commands = explode("\n", $this->content);
$result = '';
foreach ($commands as $key => $item)
{
$result .= $telnet->exec($item);
}