php无阻塞SSH客户端实例
发布时间:2022-06-21 14:21 所属栏目:121 来源:互联网
导读:之前工作中必须和国外服务器打交道,延迟和丢包问题有时候非常严重,已经到了不可忍受的地步,输入一条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();。 (编辑:ASP站长网) |
相关内容
网友评论
推荐文章
热点阅读