如何通过 PHP 执行 SSH 命令

我期待通过 PHP SSH 出来。最好/最安全的方法是什么?我知道我能做到:

shell_exec("SSH user@host.com mkdir /testing");

还有更好的吗? 感觉太“淘气”了:)。

211038 次浏览

你有 SSH2分机可用吗?

医生: http://www.php.net/manual/en/function.ssh2-exec.php

$connection = ssh2_connect('shell.example.com', 22);
ssh2_auth_password($connection, 'username', 'password');


$stream = ssh2_exec($connection, '/usr/local/bin/php -i');

使用 ssh2函数。您通过 exec ()调用所做的任何事情都可以直接使用这些函数来完成,从而为您节省了大量连接和 shell 调用。

在 php 中使用 ssh2很困难,主要是因为输出流有时可以工作,有时不能。我要在这里粘贴我的自由主义,这对我很有用。如果代码中有小的不一致,那是因为我把它插入了一个框架,但是你可以很好地移植它:

<?php


class Components_Ssh {


private $host;


private $user;


private $pass;


private $port;


private $conn = false;


private $error;


private $stream;


private $stream_timeout = 100;


private $log;


private $lastLog;


public function __construct ( $host, $user, $pass, $port, $serverLog ) {
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->port = $port;
$this->sLog = $serverLog;


if ( $this->connect ()->authenticate () ) {
return true;
}
}


public function isConnected () {
return ( boolean ) $this->conn;
}


public function __get ( $name ) {
return $this->$name;
}


public function connect () {
$this->logAction ( "Connecting to {$this->host}" );
if ( $this->conn = ssh2_connect ( $this->host, $this->port ) ) {
return $this;
}
$this->logAction ( "Connection to {$this->host} failed" );
throw new Exception ( "Unable to connect to {$this->host}" );
}


public function authenticate () {
$this->logAction ( "Authenticating to {$this->host}" );
if ( ssh2_auth_password ( $this->conn, $this->user, $this->pass ) ) {
return $this;
}
$this->logAction ( "Authentication to {$this->host} failed" );
throw new Exception ( "Unable to authenticate to {$this->host}" );
}


public function sendFile ( $localFile, $remoteFile, $permision = 0644 ) {
if ( ! is_file ( $localFile ) ) throw new Exception ( "Local file {$localFile} does not exist" );
$this->logAction ( "Sending file $localFile as $remoteFile" );


$sftp = ssh2_sftp ( $this->conn );
$sftpStream = @fopen ( 'ssh2.sftp://' . $sftp . $remoteFile, 'w' );
if ( ! $sftpStream ) {
//  if 1 method failes try the other one
if ( ! @ssh2_scp_send ( $this->conn, $localFile, $remoteFile, $permision ) ) {
throw new Exception ( "Could not open remote file: $remoteFile" );
}
else {
return true;
}
}


$data_to_send = @file_get_contents ( $localFile );


if ( @fwrite ( $sftpStream, $data_to_send ) === false ) {
throw new Exception ( "Could not send data from file: $localFile." );
}


fclose ( $sftpStream );


$this->logAction ( "Sending file $localFile as $remoteFile succeeded" );
return true;
}


public function getFile ( $remoteFile, $localFile ) {
$this->logAction ( "Receiving file $remoteFile as $localFile" );
if ( ssh2_scp_recv ( $this->conn, $remoteFile, $localFile ) ) {
return true;
}
$this->logAction ( "Receiving file $remoteFile as $localFile failed" );
throw new Exception ( "Unable to get file to {$remoteFile}" );
}


public function cmd ( $cmd, $returnOutput = false ) {
$this->logAction ( "Executing command $cmd" );
$this->stream = ssh2_exec ( $this->conn, $cmd );


if ( FALSE === $this->stream ) {
$this->logAction ( "Unable to execute command $cmd" );
throw new Exception ( "Unable to execute command '$cmd'" );
}
$this->logAction ( "$cmd was executed" );


stream_set_blocking ( $this->stream, true );
stream_set_timeout ( $this->stream, $this->stream_timeout );
$this->lastLog = stream_get_contents ( $this->stream );


$this->logAction ( "$cmd output: {$this->lastLog}" );
fclose ( $this->stream );
$this->log .= $this->lastLog . "\n";
return ( $returnOutput ) ? $this->lastLog : $this;
}


public function shellCmd ( $cmds = array () ) {
$this->logAction ( "Openning ssh2 shell" );
$this->shellStream = ssh2_shell ( $this->conn );


sleep ( 1 );
$out = '';
while ( $line = fgets ( $this->shellStream ) ) {
$out .= $line;
}


$this->logAction ( "ssh2 shell output: $out" );


foreach ( $cmds as $cmd ) {
$out = '';
$this->logAction ( "Writing ssh2 shell command: $cmd" );
fwrite ( $this->shellStream, "$cmd" . PHP_EOL );
sleep ( 1 );
while ( $line = fgets ( $this->shellStream ) ) {
$out .= $line;
sleep ( 1 );
}
$this->logAction ( "ssh2 shell command $cmd output: $out" );
}


$this->logAction ( "Closing shell stream" );
fclose ( $this->shellStream );
}


public function getLastOutput () {
return $this->lastLog;
}


public function getOutput () {
return $this->log;
}


public function disconnect () {
$this->logAction ( "Disconnecting from {$this->host}" );
// if disconnect function is available call it..
if ( function_exists ( 'ssh2_disconnect' ) ) {
ssh2_disconnect ( $this->conn );
}
else { // if no disconnect func is available, close conn, unset var
@fclose ( $this->conn );
$this->conn = false;
}
// return null always
return NULL;
}


public function fileExists ( $path ) {
$output = $this->cmd ( "[ -f $path ] && echo 1 || echo 0", true );
return ( bool ) trim ( $output );
}
}

我会使用 Phpseclib,一个纯 PHP SSH 实现。例如:

<?php
include('Net/SSH2.php');


$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'password')) {
exit('Login Failed');
}


echo $ssh->exec('pwd');
echo $ssh->exec('ls -la');
?>

对于那些使用 Symfony框架的用户,也可以使用 Phpseclib通过 SSH 进行连接。可以使用编曲器安装:

composer require phpseclib/phpseclib

接下来,简单地使用它如下:

use phpseclib\Net\SSH2;


// Within a controller for example:
$ssh = new SSH2('hostname or ip');
if (!$ssh->login('username', 'password')) {
// Login failed, do something
}


$return_value = $ssh->exec('command');

//更新 二零一八年,工程//

方法一:

下载 Phpseclib < strong > v1 并使用以下代码:

<?php
set_include_path(__DIR__ . '/phpseclib1.0.11');
include("Net/SSH2.php");


$key ="MyPassword";
/* ### if using PrivateKey ###
include("Crypt/RSA.php");
$key = new Crypt_RSA();
$key->loadKey(file_get_contents('private-key.ppk'));
*/


$ssh = new Net_SSH2('www.example.com', 22);   // Domain or IP
if (!$ssh->login('your_username', $key))  exit('Login Failed');


echo $ssh->exec('pwd');
?>

或方法2:

下载最新的 Phpseclib < strong > v2 (首先需要 composer install) :

<?php


set_include_path($path=__DIR__ . '/phpseclib-master/phpseclib');
include ($path.'/../vendor/autoload.php');


$loader = new \Composer\Autoload\ClassLoader();


use phpseclib\Net\SSH2;


$key ="MyPassword";
/* ### if using PrivateKey ###
use phpseclib\Crypt\RSA;
$key = new RSA();
$key->load(file_get_contents('private-key.ppk'));
*/


$ssh = new SSH2('www.example.com', 22);   // Domain or IP
if (!$ssh->login('your_username', $key))   exit('Login Failed');


echo $ssh->exec('pwd');
?>

如果你得到“连接超时”,那么这可能是主机/防火墙(本地或远程)或类似的问题,不是脚本的错误。