php专区

 首页 > php专区 > PHP基础 > 环境 > php无阻塞SSH客户端实例

php无阻塞SSH客户端实例

分享到:
【字体:
导读:
          之前工作中必须和国外服务器打交道,延迟和丢包问题有时候非常严重,已经到了不可忍受的地步,输入一条sql都是很费劲的事情,google搜了一遍没有找到非阻塞的ssh客户端,PHP有SSH2扩展,利用...

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

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

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

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

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

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(); 
  4.  
分享到:
PHP扩展Xdebug的安装使用实例
Xdebug是什么?它是一款可以用来调试php代码运行一款工具,下面小编来给大家介绍Xdebug安装方法,下面教程是基于linux与windows系统的. Q:xdebug是什么? A:xdebug是一个开源的php调试器,以php模块的形式加载并被使用. 上周发现xdebug出了RC(release candidate)2版了,就拿下来安装了一下,顺便写了一个安装手册,...
PHP Startup: Unable to load dynamic li...
昨天帮一朋友配置服务器结果发现apache日志中有PHP Warning: PHP Startup: Unable to load dynamic library 提示了,然后调试数据库连接发现提示Call to undefined function mysql_connect()错误,这样就想到了是mysql没有加载成功了,下面我们一起来看看问题解决办法. 连接代码:   因为服务器使用的...
  •         php迷,一个php技术的分享社区,专属您自己的技术摘抄本、收藏夹。
  • 在这里……