Je cherche à sortir SSH via PHP. Quel est le meilleur moyen/le plus sûr d’agir? Je sais que je peux faire:
Shell_exec("SSH [email protected] mkdir /testing");
Quelque chose de mieux? Cela fait tellement «vilain» :).
J'utiliserais phpseclib, une implémentation SSH PHP pure . Un exemple:
<?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');
?>
Avez-vous l'extension SSH2 disponible?
Docs: 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');
J'ai eu beaucoup de mal avec ssh2 en php principalement parce que le flux de sortie fonctionne parfois et parfois non. Je vais juste coller mon lib ici qui fonctionne très bien pour moi. S'il y a de petites incohérences dans le code, c'est parce que je l'ai branché dans un framework, mais vous devriez être en mesure de le porter:
<?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 );
}
}
Pour ceux qui utilisent le Symfony framework, le phpseclib peut également être utilisé pour se connecter via SSH. Il peut être installé en utilisant composer:
composer require phpseclib/phpseclib
Ensuite, utilisez-le simplement comme suit:
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');
Utilisez les fonctions ssh2
. Tout ce que vous feriez via un appel à exec () peut être fait directement à l'aide de ces fonctions, ce qui vous évite beaucoup de connexions et d'invocations Shell.
J'ai écrit un simple client ssh avec xterm, vous pouvez consulter le code source sur la page github https://github.com/roke22/PHP-SSH2-Web-Client
Vous pouvez m'aider à m'améliorer, envoyez-moi s'il vous plaît des commentaires.
Téléchargez phpseclib v1 et utilisez ce code:
<?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');
?>
Télécharger le plus récent phpseclib v2 (requiert composer install
au début):
<?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');
?>
p.s. si vous obtenez "Connexion expirée", c'est probablement le problème de Host/FIREWALL (local ou distant) ou similaire, pas une faute de script.