2011-06-07 418 views

回答

16

您是否有可用的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'); 
+1

無法獲取血腥SSH2模塊去,漸漸在錯誤日誌中的以下內容:PHP的警告:PHP啓動:SSH2:無法初始化模塊 模塊與模塊API = 20050922 PHP編譯編譯與模塊API = 20090626 這些選項需要匹配 未知的行0 – Justin 2011-06-07 19:34:20

+0

什麼操作系統和版本,以及什麼PHP版本? – 2011-06-07 19:39:12

+2

另請注意,您必須擁有OpenSSL和libssh2才能使ssh2模塊正常工作。如果您手動構建PHP,則必須確保您具有兩個所需模塊的兼容版本。該錯誤表示版本不匹配。 – 2011-06-07 19:41:18

2

使用ssh2功能。任何通過exec()調用完成的任務都可以使用這些函數直接完成,爲您節省大量連接和shell調用。

10

我在PHP中使用ssh2很困難,主要是因爲輸出流有時會起作用,有時卻不起作用。我只是要把我的lib放在這裏,這對我很好。如果在代碼不一致小是因爲我把它插在一個框架,但你應該罰款將它移植:

<?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

謝謝!這一個幫助了很多。我重寫了它使用公鑰/私鑰身份驗證,但睡眠(1)殺死了我的生產力。如果我有時間想出解決辦法,我會讓你知道。謝謝! – jbrahy 2014-10-13 22:01:48

62

我會用phpseclib, a pure PHP SSH implementation。舉個例子:

<?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

這些可以是異步的嗎?我需要同時與多個系統通話 - 我可以啓動多個ssh會話,然後「選擇」(或輪詢)所有這些會話嗎?.. – 2013-11-01 04:25:44

+2

有點。真的,你的問題會更適合作爲一個新的而不是回覆,但無論如何。您可以爲每個$ ssh實例執行'$ ssh-> setTimeout(...)'並循環執行它們。互動模式可能對你更好,因爲閱讀和寫作有點不相干。同樣的,你可以做enablePTY()我猜想''ssh-> exec()'用'ssh-> read()'/'$ ssh-> write()'。 – neubert 2014-01-02 21:57:34

+0

請注意,這個庫不支持readlink() – Alexander 2014-03-27 16:43:56