当前位置:首页 > PHP教程 > php环境安装 > 列表

php无阻塞SSH客户端实例

发布:smiling 来源: PHP粉丝网  添加日期:2014-08-25 16:32:31 浏览: 评论:0 

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

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

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

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

  1. <?php 
  2. class FSSH{ 
  3.  private $conn
  4.  private $shell
  5.  
  6.  /** 
  7.  * key=String 密码认证,key=array('pub'=>,'pri'=>,'type'=>,'phrase'=>)密钥认证 
  8.  * 密钥认证type分为两种:ssh-rsa,ssh-dss  
  9.  * $host[addr]=String 地址,$host['fp']=array() 服务器指纹 
  10.  */ 
  11.  function __construct($host,$user,$key){ 
  12.   if(emptyempty($host['addr'])){ 
  13.    debug_print('Host cant't be emptyempty',E_USER_ERROR); 
  14.   } 
  15.   if(emptyempty($host['fp'])){ 
  16.    debug_print('finger print is not specified',E_USER_ERROR); 
  17.   }//开源代码phpfensi.com 
  18.   $this->stdin=fopen('php://stdin','r'); 
  19.   $this->stdout=fopen('php://stdout','w'); 
  20.   if(false!==strpos($host['addr'],':')){ 
  21.    $temp=explode(':',$host['addr']); 
  22.    $host['addr']=$temp[0]; 
  23.    $port=$temp[1]; 
  24.   }else
  25.    $port=22; 
  26.   } 
  27.   if(is_string($key) || emptyempty($key['type'])){ 
  28.    $methods=null; 
  29.   }else
  30.    $methods=array('hostkey'=>$key['type']); 
  31.   } 
  32.   $conn=ssh2_connect($host['addr'],$port,$methods,array('disconnect'=>array($this,'disconnect'))); 
  33.   $fp=ssh2_fingerprint($conn,SSH2_FINGERPRINT_MD5); 
  34.   $success=false; 
  35.   $fpOK=false; 
  36.   if(in_array($fp,$host['fp'])){ 
  37.    $fpOK=true; 
  38.   }else
  39.    fwrite($this->stdout,"$fpnIs fingerprint OK ?(y/n)"); 
  40.    $input=strtolower(stream_get_line($this->stdin,1)); 
  41.    if($input=='y'){ 
  42.     $fpOK=true; 
  43.    }else
  44.     $fpOK=false; 
  45.    } 
  46.   } 
  47.   if($fpOK){ 
  48.    if(is_array($key)){ 
  49.     if (ssh2_auth_pubkey_file($conn,$user,$key['pub'],$key['pri'],$key['phrase'])){ 
  50.      $success=true; 
  51.     }else
  52.      debug_print('Public Key Authentication Failed',E_USER_ERROR); 
  53.     } 
  54.    }elseif(is_string($key)){ 
  55.     if(ssh2_auth_password($conn,$user,$key)){ 
  56.      $success=true; 
  57.     }else
  58.      debug_print('Password Authentication Failed',E_USER_ERROR); 
  59.     } 
  60.    } 
  61.   }else
  62.    debug_print('Fingerprint is invalid',E_USER_ERROR); 
  63.   } 
  64.   if($success){ 
  65.    $this->conn=$conn
  66.    $this->shell=ssh2_shell($conn,null,null,1024); 
  67.   } 
  68.   return $success
  69.  } 
  70.  
  71.  function shell(){ 
  72.   //最后一条命令 
  73.   $last=''
  74.   //先结束shell,再结束while 
  75.   $signalTerminate=false; 
  76.   while(true){ 
  77.    $cmd=$this->fread($this->stdin); 
  78.    $out=stream_get_contents($this->shell,1024); 
  79.    if(!emptyempty($outand !emptyempty($last)){ 
  80.     $l1=strlen($out); 
  81.     $l2=strlen($last); 
  82.     $l=$l1>$l2?$l2:$l1
  83.     $last=substr($last,$l); 
  84.     $out=substr($out,$l); 
  85.    } 
  86.    echo ltrim($out); 
  87.    if($signalTerminate){ 
  88.     break
  89.    } 
  90.    if(in_array(trim($cmd),array('exit'))){ 
  91.     $signalTerminate=true; 
  92.    } 
  93.    if(!emptyempty($cmd)){ 
  94.     $last=$cmd
  95.     fwrite($this->shell,$cmd); 
  96.    } 
  97.   } 
  98.  } 
  99.  
  100.  //解决windows命令行的读取问题,没有别的办法了。 
  101.  private function fread($fd){ 
  102.   static $data=''
  103.   $read = array($fd); 
  104.   $write = array(); 
  105.   $except = array(); 
  106.   $result = stream_select($read,$write,$except,0,1000); 
  107.   if($result === false) 
  108.    debug_print('stream_select failed',E_USER_ERROR); 
  109.   if($result !== 0){ 
  110.    $c= stream_get_line($fd,1); 
  111.    if($c!=chr(13)) 
  112.     $data.=$c
  113.    if($c==chr(10)){ 
  114.     $t=$data
  115.     $data=''
  116.     return $t
  117.    } 
  118.   } 
  119.  } 
  120.  
  121.  function __destruct(){ 
  122.   fclose($this->stdin); 
  123.   fclose($this->stdout); 
  124.   $this->disconnect(); 
  125.  } 
  126.  
  127.  private function disconnect(){ 
  128.   if(is_resource($this->conn)){ 
  129.    unset($this->conn); 
  130.    fclose($this->shell); 
  131.   } 
  132.  } 
  133. ?> 

demo,代码如下:

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

Tags: php客户端 SSH客户端

分享到: