Heim >php教程 >php手册 >php无阻塞SSH客户端实例

php无阻塞SSH客户端实例

WBOY
WBOYOriginal
2016-06-13 09:49:581072Durchsuche

之前工作中必须和国外服务器打交道,延迟和丢包问题有时候非常严重,已经到了不可忍受的地步,输入一条sql都是很费劲的事情。google搜了一遍没有找到非阻塞的ssh客户端,PHP有SSH2扩展,利用标准输入输出理论上可以实现一个基于命令的SSH客户端,这样就解决了网络问题带来的不便,于是开发了一个PHP非阻塞SSH客户端

价值:

  • 基于命令,最大程度解决了网络延迟和丢包问题。
  • windows和Linux下测试通过。

不足:

  • 没有自动补全功能
  • 没有sftp和scp等其他功能
  • 没有颜色和粗体显示
  • 个别情况下显示上不是很完美
  • 因为现在基本不用它了,所以暂时先不进行改进。

linux 运行效果

windows下运行效果


因为是框架中的一个类,所以个别通用函数(比如debug_print())需要自己提供,我这里就不改写了

 代码如下 复制代码

class FSSH{
 private $conn;
 private $shell;

 /**
 * key=String 密码认证,key=array('pub'=>,'pri'=>,'type'=>,'phrase'=>)密钥认证
 * 密钥认证type分为两种:ssh-rsa,ssh-dss
 * $host[addr]=String 地址,$host['fp']=array() 服务器指纹
 */
 function __construct($host,$user,$key){
  if(empty($host['addr'])){
   debug_print('Host cant't be empty',E_USER_ERROR);
  }
  if(empty($host['fp'])){
   debug_print('finger print is not specified',E_USER_ERROR);
  }
  $this->stdin=fopen('php://stdin','r');
  $this->stdout=fopen('php://stdout','w');
  if(false!==strpos($host['addr'],':')){
   $temp=explode(':',$host['addr']);
   $host['addr']=$temp[0];
   $port=$temp[1];
  }else{
   $port=22;
  }
  if(is_string($key) || empty($key['type'])){
   $methods=null;
  }else{
   $methods=array('hostkey'=>$key['type']);
  }
  $conn=ssh2_connect($host['addr'],$port,$methods,array('disconnect'=>array($this,'disconnect')));
  $fp=ssh2_fingerprint($conn,SSH2_FINGERPRINT_MD5);
  $success=false;
  $fpOK=false;
  if(in_array($fp,$host['fp'])){
   $fpOK=true;
  }else{
   fwrite($this->stdout,"$fpnIs fingerprint OK ?(y/n)");
   $input=strtolower(stream_get_line($this->stdin,1));
   if($input=='y'){
    $fpOK=true;
   }else{
    $fpOK=false;
   }
  }
  if($fpOK){
   if(is_array($key)){
    if (ssh2_auth_pubkey_file($conn,$user,$key['pub'],$key['pri'],$key['phrase'])){
     $success=true;
    }else{
     debug_print('Public Key Authentication Failed',E_USER_ERROR);
    }
   }elseif(is_string($key)){
    if(ssh2_auth_password($conn,$user,$key)){
     $success=true;
    }else{
     debug_print('Password Authentication Failed',E_USER_ERROR);
    }
   }
  }else{
   debug_print('Fingerprint is invalid',E_USER_ERROR);
  }
  if($success){
   $this->conn=$conn;
   $this->shell=ssh2_shell($conn,null,null,1024);
  }
  return $success;
 }

 function shell(){
  //最后一条命令
  $last='';
  //先结束shell,再结束while
  $signalTerminate=false;
  while(true){
   $cmd=$this->fread($this->stdin);
   $out=stream_get_contents($this->shell,1024);
   if(!empty($out) and !empty($last)){
    $l1=strlen($out);
    $l2=strlen($last);
    $l=$l1>$l2?$l2:$l1;
    $last=substr($last,$l);
    $out=substr($out,$l);
   }
   echo ltrim($out);
   if($signalTerminate){
    break;
   }
   if(in_array(trim($cmd),array('exit'))){
    $signalTerminate=true;
   }
   if(!empty($cmd)){
    $last=$cmd;
    fwrite($this->shell,$cmd);
   }
  }
 }

 //解决windows命令行的读取问题,没有别的办法了。
 private function fread($fd){
  static $data='';
  $read = array($fd);
  $write = array();
  $except = array();
  $result = stream_select($read,$write,$except,0,1000);
  if($result === false)
   debug_print('stream_select failed',E_USER_ERROR);
  if($result !== 0){
   $c= stream_get_line($fd,1);
   if($c!=chr(13))
    $data.=$c;
   if($c==chr(10)){
    $t=$data;
    $data='';
    return $t;
   }
  }
 }

 function __destruct(){
  fclose($this->stdin);
  fclose($this->stdout);
  $this->disconnect();
 }

 private function disconnect(){
  if(is_resource($this->conn)){
   unset($this->conn);
   fclose($this->shell);
  }
 }
}


demo

 代码如下 复制代码

//$ssh=new FSSH(array('addr'=>'x.x.x.x:22','fp'=>array('')),'tunnel',array('pub'=>'E:Identity.pub','pri'=>'E:Identity','type'=>'ssh-rsa'));
$ssh=new FSSH(array('addr'=>'192.168.2.205','fp'=>array('54ECC700B844DCF0D40554A56C57C01E')),'root','123456');
$ssh->shell();

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:php 删除目录Nächster Artikel:Windows2000下安装ApachePHP4MySQL