70 votes

Comment exécuter des commandes SSH via PHP ?

Je cherche à établir une connexion SSH via PHP. Quelle est la meilleure façon de procéder ? Je sais que je peux le faire :

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

Rien de mieux ? C'est tellement "coquin" :).

0 votes

Puis-je savoir pourquoi vous pensez que ce n'est pas le meilleur moyen de sécurité ? Je suis curieux !

79voto

J'utiliserais phpseclib, une implémentation SSH purement PHP . 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');
?>

1 votes

Peuvent-ils être asynchrones ? J'ai besoin de parler à plusieurs systèmes à la fois - puis-je lancer plusieurs sessions ssh et ensuite "sélectionner" (ou interroger) sur tous ces systèmes ?

2 votes

Kinda. Vraiment, ta question serait plus appropriée en tant que nouvelle question qu'en tant que réponse, mais peu importe. Vous pourriez faire $ssh->setTimeout(...) pour chaque instance de $ssh et les parcourir. Le mode interactif pourrait être meilleur pour vous aussi, car la lecture et l'écriture y sont en quelque sorte disjointes. De la même manière, vous pouvez utiliser enablePTY() pour utiliser $ssh->exec() con $ssh->read() / $ssh->write() .

0 votes

Je ne pense pas que SFTP, en tant que protocole, supporte readlink(). Si vous connaissez des implémentations SFTP qui supportent readlink(), je serais curieux de les connaître.

24voto

Chris Points 20836

Disposez-vous de l'extension SSH2 ?

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

1 votes

Je n'arrive pas à faire fonctionner le module SSH2, j'obtiens le résultat suivant dans le journal des erreurs : PHP Warning:Démarrage de PHP : ssh2 : Unable to initialize module Module compilé avec le module API=20050922 PHP compilé avec le module API=20090626 Ces options doivent correspondre dans Unknown on line 0

0 votes

Quel système d'exploitation et quelle version, et quelle version de PHP ?

2 votes

Notez également que vous devez avoir OpenSSL et libssh2 pour que le module ssh2 fonctionne correctement. Si vous compilez manuellement PHP, vous devez vous assurer que vous avez des versions compatibles des deux modules requis. Cette erreur indique un désaccord entre les versions.

13voto

Romeo M. Points 895

J'ai eu du mal avec ssh2 en php, principalement parce que le flux de sortie fonctionne parfois et parfois non. Je vais juste coller ma librairie 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 inséré dans un framework, mais vous devriez pouvoir le porter sans problème :

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

1 votes

Merci ! Celui-ci m'a beaucoup aidé. Je l'ai réécrit pour utiliser l'authentification par clé publique / privée mais le sleep(1) tue ma productivité. Si j'ai le temps de trouver une solution, je vous le ferai savoir. Merci !

1 votes

Il manque logAction La définition de l'UE ?

9voto

Ziad Akiki Points 1677

Pour ceux qui utilisent le Symfony cadre, le site phpseclib peut également être utilisé pour se connecter via SSH. Il peut être installé à l'aide de composer :

composer require phpseclib/phpseclib

Ensuite, il suffit de l'utiliser 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');

4 votes

Pour mémoire : ceci n'a rien à voir avec Symfony. Si vous avez un projet PHP quelconque, vous pouvez ajouter/appliquer la dépendance du compositeur et utiliser le code ci-dessus.

0 votes

Vous devrez peut-être utiliser use phpseclib3\Net\SSH2;

8voto

snm-yah Points 2067

//Mise à jour 2018 , fonctionne//

Méthode1 :

Télécharger 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 la méthode 2 :

Téléchargement le plus récent phpseclib v2 (nécessite 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 "Connection timed out" alors c'est probablement le problème de HOST/FIREWALL (local ou distant) ou similaire, pas une faute de script.

0 votes

Fonctionne toujours sur 2021, mais vous devez mettre à jour à la v3. include ('vendor/autoload.php'); $loader = new \Composer\Autoload\ClassLoader(); use phpseclib3\Net\SSH2;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X