加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_宿迁站长网 (https://www.0527zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

php无阻塞SSH客户端实例

发布时间:2022-06-22 09:35:12 所属栏目:PHP教程 来源:互联网
导读:之前工作中必须和国外服务器打交道,延迟和丢包问题有时候非常严重,已经到了不可忍受的地步,输入一条sql都是很费劲的事情,google搜了一遍没有找到非阻塞的ssh客户端,PHP有SSH2扩展,利用标准输入输出理论上可以实现一个基于命令的SSH客户端,这样就解决了网络
  之前工作中必须和国外服务器打交道,延迟和丢包问题有时候非常严重,已经到了不可忍受的地步,输入一条sql都是很费劲的事情,google搜了一遍没有找到非阻塞的ssh客户端,PHP有SSH2扩展,利用标准输入输出理论上可以实现一个基于命令的SSH客户端,这样就解决了网络问题带来的不便,于是开发了一个PHP非阻塞SSH客户端.
 
  价值:基于命令,最大程度解决了网络延迟和丢包问题,windows和Linux下测试通过.
 
  不足:没有自动补全功能,没有sftp和scp等其他功能,没有颜色和粗体显示,个别情况下显示上不是很完美,因为现在基本不用它了,所以暂时先不进行改进.
 
  因为是框架中的一个类,所以个别通用函数(比如debug_print())需要自己提供,我这里就不改写了,代码如下:
 
  <?php
  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(emptyempty($host['addr'])){
     debug_print('Host cant't be emptyempty',E_USER_ERROR);
    }
    if(emptyempty($host['fp'])){
     debug_print('finger print is not specified',E_USER_ERROR);
    }//开源代码phpfensi.com
    $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) || emptyempty($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(!emptyempty($out) and !emptyempty($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(!emptyempty($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();。
 

(编辑:云计算网_宿迁站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!