PHP Conference Japan 2024

ssh2_shell

(PECL ssh2 >= 0.9.0)

ssh2_shell請求互動式 Shell

說明

ssh2_shell(
    資源 $session,
    字串 $termtype = "vanilla",
    ?陣列 $env = null,
    整數 $width = 80,
    整數 (int) $height = 25,
    整數 (int) $width_height_type = SSH2_TERM_UNIT_CHARS
): 資源 (resource)|false

在遠端開啟一個 shell 並且分配一個串流給它。

參數

session

一個 SSH 連線識別碼,由呼叫 ssh2_connect() 取得。

termtype

termtype 應該對應目標系統 /etc/termcap 檔案中的一個項目。

env

env 可以作為名稱/值對的關聯陣列傳遞,以設定目標環境。

width

虛擬終端機的寬度。

height

虛擬終端機的高度。

width_height_type

width_height_type 應該是 SSH2_TERM_UNIT_CHARSSSH2_TERM_UNIT_PIXELS 其中之一。

回傳值

成功時返回一個串流 資源,失敗時返回 false

範例

範例 #1 請求一個互動式 shell

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

$stream = ssh2_shell($connection, 'vt102', null, 80, 24, SSH2_TERM_UNIT_CHARS);
?>

參見

新增筆記

使用者貢獻的筆記 9 則筆記

stefanov at uk dot ibm dot com
16 年前
不要使用 \n 來結束指令。有些伺服器將無法處理。請務必使用 PHP 的標準換行符號:PHP_EOL

「suri at suribala dot com」的範例應該修改如下(同時將雙引號改為單引號,以獲得更好的效能)

<?php

$con
=ssh2_connect('192.168.0.1', 22);
ssh2_auth_password($con, 'user', 'password');
$shell=ssh2_shell($con, 'xterm');
fwrite( $shell, 'cd /dir_one;'.PHP_EOL);
fwrite( $shell, 'ls -la;'.PHP_EOL);
fwrite( $shell, 'cd /dir_two;'.PHP_EOL);
fwrite( $shell, 'ls -la;'.PHP_EOL);

?>

敬上,

Pimmy
tuxedobob at mac dot com
10 年前
請記住,使用 ssh2_shell 時,遠端系統的 EOL 可能與 PHP 的 EOL 不同,因此使用 PHP_EOL 可能不安全。 Windows 的原生 EOL 是 \r\n,而 Unix 通常只是 \n,而經典 Mac 則是 \r。

如果您在 Windows (\r\n) 上運行 PHP 並透過 SSH 連接到 Unix 系統 (\n),您最終會發送額外的行。到目前為止,我的經驗是它就像您什麼也沒輸入一樣,這可能會導致密碼提示出現問題。

喔,還有 \n\r? 別這樣做。 沒有人這樣做。
galvao at galvao dot eti dot br
17 年前
回覆 webmaster at spectreanime dot com

「由於某些不明原因,就在你的指令之後,你需要讓它 sleep 一下,以確保指令已到達伺服器並正在運行」

實際上,您必須將字串的 blocking 設為 true,這樣它會等到伺服器將數據發送到 STDOUT 後才會輸出。

所以,不要

sleep(1);

只要這樣做

stream_set_blocking($stdio, true);

此致,
webmaster at spectreanime dot com
19 年前
// 連線到 SSH 伺服器
echo "SSH 連線 ";
if (!($resource=@ssh2_connect("192.168.0.1"))) {
echo "[失敗]<br />";
exit(1);
}
echo "[成功]<br />";

// 使用帳號/密碼驗證
echo "驗證 ";
if (!@ssh2_auth_password($resource,"root","your_password")) {
echo "[失敗]<br />";
exit(1);
}
echo "[成功]<br />";

// 我們需要一個 shell
echo "Shell stdio ";
if (!($stdio = @ssh2_shell($resource,"xterm"))) {
echo "[失敗]<br />";
exit(1);
}
echo "[成功]<br />";

// 執行任何指令
// 注意在指令末尾加上 '\n'
$command = "/bin/ls /tmp\n";
fwrite($stdio,$command);

// 重要
// 基於某些難以理解的原因,在你發送指令後,你需要讓程式 sleep 一下,以確保指令已送達伺服器並正在執行
sleep(1);

// 然後你可以擷取串流,看看標準輸出 (stdio) 上發生了什麼事
while($line = fgets($stdio)) {
flush();
echo $line."<br />";
}

// 關閉所有串流通常是比較好的做法
fclose($stdio);

衷心希望我能幫助到某些人 :)
josh at hydril dot com
17 年前
要以互動式登入時擁有的所有變數來執行 shell script,請在你的指令前加上 bash -l 或 sh --login。我使用的 script 會建立一個 shell script,使用 ssh2_scp_send 將 script 複製到機器上,然後使用 ssh2_exec 執行該 script。希望這能幫助到某些人。

<?php

//範例

$script1 = "bash -l /etc/rc.d/rc.httpd restart";

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

$stream = ssh2_exec($connection, $script1);
?>
vgopu1 at gmail dot com
17 年前
嗨,

我們也可以使用 shell_exec 來執行多個相關的指令
以分號 (;) 分隔。

我發現了與執行複雜的 Java、C/C++ 程式相關的問題。我們只需要設定必要的環境變數。我在 .bash_profile 中有一個環境變數。當我透過 shell 正常登入我的帳號時,這個變數會被設定。但是當我們使用 ssh2_connect() 時,.bash_profile 中的環境變數不會被設定,我們需要做的就是使用 shell_exec() 匯出所需的環境變數。

範例

$conn = ssh2_connect($ipaddress);
ssh2_auth_password($conn,$username,$passwd);
$cmd1="/path/to/program1";
$cmd2="/path/to/program2";
$env1="export Variable_name1=path1";
$env2="export Variable_name2=path2"
$stream = ssh2_exec($connection,"$env1; $env2; $cmd1; $cmd2");//這會執行所有指令並回傳
// 串流
stream_set_blocking($stream, true);
while($o=fgets($stream)){
echo $o.'<br>';
}

...
...

謝謝,
Vikram Gopu .
http:\\my.lsu.edu/vgopu1
nogueiraconsultoria at gmail dot com
4 年前
我寫了一個可以執行多個指令的 script。這個 script 會將每個指令的輸出以陣列形式回傳,並以「指令」作為索引。

注意:ssh2_cmd() 不適用於多個指令,因此請使用 ssh2_shell()。請注意不同作業系統的換行字元。我在每個指令的結尾使用了「\n」,但也許可以使用其他選項,例如「<br>、; 等等)。

$connection = ssh2_connect($input_host_ip, 22);

if (false === $connection) {
error_log("ERROR 函式 SSH_UMTELECOM:連線失敗!\n",3,$log_file);
exit();
}else{
if($debugar){error_log("SSH_UMTELECOM: 連線至 $input_host_ip 成功!\n",3,$log_file);}

$auth = @ssh2_auth_password($connection, $user, $pass);
if (false === $auth) {
error_log("錯誤 函式 SSH_UMTELECOM: 在 $input_host_ip 上驗證失敗 (使用者: $user)!\n",3,$log_file);
exit();
}else{
if($debugar){error_log("SSH_UMTELECOM: 在 $input_host_ip 上驗證成功!\n",3,$log_file);}

error_log("開始串流: $connection\n",3,$log_file);
$output_array = array();
$shell = ssh2_shell($connection, 'vt100');

foreach($input_cmd as $cmd){
if($debugar){error_log("shell: $cmd\n",3,$log_file);}
$output_stream = ""; # 清空變數,供每次互動使用
fwrite($shell, "$cmd\n"); # 每個指令結束時別忘了加上 "\n"
#stream_set_blocking($shell, true); # 無法運作,會無限期等待
sleep(2); # 適用於高延遲網路的 2 秒延遲
while($output_streams = fgets($shell)){
$output_stream .= $output_streams;
flush();# 清空內容,供下次互動使用
}
$output_array[] = $output_stream; # 將每個回傳值與其對應的指令彙整在一起
}
fclose($shell); # 從 shell 正常登出
}# if false === $auth 結束
}# if false === $conenection 結束
tsschulz at gmx dot net
13 年前
就我的情況而言,ssh2_shell 並非每次都能正常運作。 存在許多問題
- 如果我使用 stream_get_contents,指令永遠不會執行
- 使用 while ($buf = fgets...) 時,迴圈永遠不會停止
- 在 stream_set_blocking 之前沒有 sleep(1) 的話,指令並非每次都能執行。 有人知道原因嗎?
這就是我的做法,而且它有效 - 但我認為這不是它應有的樣子
<?php
$strCommand
= 'tar -C /path/to/extract -xjf /path/from/file.tar.bz2';
$sshStream = ssh2_shell($this->sshSession, 'xterm', null, 120, 24, SSH2_TERM_UNIT_CHARS);
fwrite($sshStream, $strCommand . PHP_EOL);
sleep(1);
stream_set_blocking($sshStream, true);
$sshUntarRetval = "";
while (
$buf = fgets($sshStream,4096)) {
flush();
$sshUntarRetval .= $buf;
if (
strpos($buf, 'tar -C') !== false)
{
break;
}
}
fclose($sshStream);
?>
suri at suribala dot com
19 年前
使用 ssh_exec 一次只能執行一個指令。 然而,ssh_shell 提供了更大的彈性。

以下是一個範例

<?php

$con
=ssh2_connect('192.168.0.1', 22);
ssh2_auth_password($con, "user", "password");
$shell=ssh2_shell($con, 'xterm');
fwrite( $shell, "cd /dir_one\n");
fwrite( $shell, "ls -la\n");
fwrite( $shell, "cd /dir_two\n");
fwrite( $shell, "ls -la\n");

?>

感謝 Sara 的實作和協助!
To Top