web-dev-qa-db-fra.com

Comment exécuter des commandes SSH via PHP

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» :).

54
Justin

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');
?>
64
user734976

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');
17
Chris Baker

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 );
    }
}
10
Romeo M.

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');
3
Ziad Akiki

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.

2
Marc B

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.

0
Roke

// Mise à jour 2018, fonctionne //

Méthode1:

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');
?>

ou Méthode2:

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.

0
T.Todua