有一个特殊需求,需要远程在管理多台主机,执行一些命令操作,又不想在远程机器上多装程序或者做接口。考虑了几个方案,nginx+lua,nginx+python,都比较麻烦。想来想去,干脆直接php执行shell好了。查了一下,有libssh2+ssh2的方案,了解之后觉得还不错,只需要在主控一端安装,并且是熟悉的PHP。于是装了个试试,封装了一下常用的几个ssh操作。
在Mac OS X上,通过brew安装libssh2,brew install libssh2 --build-from-source,安装好之后使用pecl安装ssh2扩展,pecl install ssh2 channel://pecl.php.net/ssh2-0.12,没有开启pecl的后面看通过源码安装,安装成功之后到php.ini当中添加extension,然后通过php -i | grep ssh看一下是不是有ssh了。
在Linux上,比如CentOS,可以通过yum install libssh2 libssh2-devel来安装。php的ssh扩展除了通过上方pecl方式安装之外,可以通过源码安装。从http://pecl.php.net/package/ssh2下载最新的源码包后参考下面的过程安装
tar vxzf ssh2-version.tgz cd ssh2-version phpize ./configure --with-ssh2 make make install
接下来到您php安装的扩展目录当中去找刚编译出来的so文件,比如我的在/usr/local/php/lib/php/extensions/no-debug-zts-20121212/目录下ssh2.so。到php.ini中添加一行extention=/path/to/ssh2.so。这样安装之后同样可以通过php -i | grep ssh查看是否成功安装模块。
下面的内容是我封装的常用的ssh操作,包括执行命令,sftp的get和put,文件操作,包括mkdir,rmdir,rename,rm,file。具体看代码吧。
class SSH {
private $connection;
private $host;
private $port;
private $username;
private $password;
function __construct($host,$port,$username,$password){
$this->host=$host;
$this->port=$port;
$this->username=$username;
$this->password=$password;
}
private function connect(){
if(!$this->connection)
{
$this->connection=ssh2_connect($this->host,$this->port);
if($this->connection)
{
if(!ssh2_auth_password($this->connection,$this->username,$this->password))
throw new Exception('Fail to login with {$this->username}:PASSWORD[YES]');
}
else
throw new Exception("Fail connect server {$this->host}:{$this->port}");
}
}
public function execute($command){
if(!$this->connection)
$this->connect();
$stream=ssh2_exec($this->connection,$command);
stream_set_blocking($stream,true);
return trim(stream_get_contents($stream));
}
public function shell($type='xterm',$env=array(),$width=80,$height=25,$width_height_type=SSH2_TERM_UNIT_CHARS){
if (!$this->connection)
$this->connect();
return ssh2_shell($this->connection,$type,$env,$width,$height,$width_height_type);
}
public function put($remote_path,$local_path,$mode=0644){
if (!$this->connection)
$this->connect();
return ssh2_scp_send($this->connection,$local_path,$remote_path,$mode);
}
public function get($remote_path,$local_path){
if (!$this->connection)
$this->connect();
return ssh2_scp_recv($this->connection,$remote_path,$local_path);
}
public function file($file){
if (!$this->connection)
$this->connect();
$sftp = ssh2_sftp($this->connection);
if ($sftp)
return ssh2_sftp_stat($sftp,$file);
else
return false;
}
public function mkdir($path,$mode=0777){
if(!$this->connection)
$this->connect();
$sftp = ssh2_sftp($this->connection);
if ($sftp)
return ssh2_sftp_mkdir($sftp,$path,$mode,true);
else
return false;
}
public function rmdir($path){
if (!$this->connection)
$this->connect();
$sftp=ssh2_sftp($this->connection);
if($sftp)
return ssh2_sftp_rmdir($sftp,$path);
else
return false;
}
public function mv($old,$new){
if (!$this->connection)
$this->connect();
$sftp = ssh2_sftp($this->connection);
if ($sftp)
return ssh2_sftp_rename($sftp,$old,$new);
else
return false;
}
public function rm($file){
if (!$this->connection)
$this->connect();
$sftp = ssh2_sftp($this->connection);
if ($sftp)
return ssh2_sftp_unlink($sftp,$file);
else
return false;
}
}虽说通过这个ssh2执行命令是没有问题,但是对于返回内容的处理还是比较麻烦的,实际返回内容是命令执行后显示的字符串,通过函数能够得到的也是完整的内容字符串,因此上面的封装当中也是直接将字符串内容返回,至于这当中的内容要怎么处理只能在后面的操作当中另行处理了,也建议在执行一些命令时不妨通过管道将内容通过grep或者awk或者sed处理一下,这样在判断结果时候可能会略方便一些。
W3c0.com 提供的内容仅用于培训。我们不保证内容的正确性。通过使用本站内容随之而来的风险与本站无关。W3c0 简体中文版的所有内容仅供测试,对任何法律问题及风险不承担任何责任。 当使用本站时,代表您已接受了本站的使用条款和隐私条款。版权所有,保留一切权利。 鲁ICP备15022115号