如何使用PHP设置交互式SSH会话?

如何使用PHP设置交互式SSH会话?,php,openssh,pty,proc-open,Php,Openssh,Pty,Proc Open,我试图通过MacOSX10.6上的命令行,使用PHP建立到远程服务器的交互式SSH连接。我目前正在使用PHP的proc_open函数执行以下命令: ssh -t -t -p 22 user@server.com 这几乎奏效了。-t-t选项应该强制一个伪终端,它们几乎都是这样做的。我可以输入SSH密码并按enter键。但是,按enter键后,终端似乎只是挂起。没有输出,什么都没有——就好像SSH会话失败了一样。我不能运行命令或其他任何东西,必须使用Ctrl+C终止整个过程。我知道登录是成功的,因

我试图通过MacOSX10.6上的命令行,使用PHP建立到远程服务器的交互式SSH连接。我目前正在使用PHP的proc_open函数执行以下命令:

ssh -t -t -p 22 user@server.com
这几乎奏效了。
-t-t
选项应该强制一个伪终端,它们几乎都是这样做的。我可以输入SSH密码并按enter键。但是,按enter键后,终端似乎只是挂起。没有输出,什么都没有——就好像SSH会话失败了一样。我不能运行命令或其他任何东西,必须使用Ctrl+C终止整个过程。我知道登录是成功的,因为我可以执行类似
ssh-t-t-p22的命令user@server.com“ls-la”
并获得正确的输出

我认为问题一定与我在proc_open调用中使用标准管道有关,所以我用pty替换了它们。我得到以下错误:“此系统不支持pty伪终端…”

Mac OS X不支持pty或伪终端吗?(我对使用所有这些shell术语非常陌生)

以下是PHP代码:

$descriptorspec = array(0 => array("pty"), 1 => array("pty"), 2 => array("pty"));  
$cwd = getcwd();  
$process = proc_open('ssh -t -t -p 22 user@server.com', $descriptorspec, $pipes, $cwd);  
if (is_resource($process))  
{  
    while (true)  
    {  
        echo(stream_get_contents($pipes[1]));  
        $status = proc_get_status($process);  
        if (! $status["running"])  
            break;  
    }  
} 
(对不起,我一辈子都搞不懂SO的格式说明…)


我做错了什么?为什么我不能使用pty?这在MacOSX上是不可能的吗?谢谢你的帮助

您应该使用公钥身份验证,而不是试图通过编程绕过交互式密码身份验证

密码提示应该是从tty使用的,我相信它是故意让人难以使用的。另外,
-t-t
参数仅在连接到远程主机后生效。我不相信PHP函数
proc_open()
可以在虚拟终端中运行命令

要设置公钥身份验证,请执行以下操作:


或者,您可以使用
plink
(PuTTY for Linux的一部分)代替OpenSSH,因为它可以在命令行
plink-pw password example.com
上获取密码但是这样做会带来安全风险,因为在服务器上运行
ps aux
的任何人都可以在进程列表中看到密码


还有一个名为
sshpass
的程序,它从环境变量或命令参数中获取密码,并将其传递给
ssh
您是否尝试过这个?

看起来问题最好使用PHP的passthru()函数来解决。经过更多(相当痛苦)的研究后,我能够通过这个函数发出命令,并且可以通过终端与远程服务器交互,就像我手动运行ssh和svn导出一样(它们都需要密码,因此是很好的测试)。我要做的是构造一个(可能很长)由
&
分隔的命令字符串,并将它们附加到ssh命令的末尾:
ssh-t-t-p22 hostname command1&&command2…
输出将发送到Mac OS X中的我的终端,即使这些命令正在远程服务器上执行。看起来这就是我一直在寻找的解决方案——非常简单!感谢所有帮助过我的人。我给Alexandre打了个“绿色勾号”,因为他是唯一一个一直在回答的人,并且在推断问题的最终答案时非常有帮助。谢谢亚历山大

你试过了吗


这是很古老的,但对于任何谷歌用户来说,这里有一个使用proc\u open的实际解决方案:

Pty描述符在PHP中可用,但必须在编译过程中进行配置(参见这篇10年前的错误报告)

但是在python中,我们没有这个问题。因此,不要直接运行ssh命令,而是运行以下python脚本:

import sys
import pty

args = " ".join(sys.argv[1:])
pty.spawn(['/usr/bin/ssh', args])
关于python文档中的pty.spawn:

生成一个进程,并将其控制终端与当前 进程的标准io。这经常被用来阻碍那些 坚持从控制终端读取数据


我在php上编写了一个ssh客户端,扩展名为ssh2,您可以在github页面上查看源代码


请发送一些反馈。

我已经为您修改了格式。要格式化代码块,只需在每行代码的开头添加四个空格。要格式化内联代码示例,请使用backticks
`
。如果您指定从PHP打开SSH的原因,也许我们可以找到其他方法来完成您尝试执行的操作。我尝试在PHP中打开SSH连接,因为我正在开发一个部署框架,该框架将自动将代码部署到远程服务器,有点像卡皮斯特拉诺。它的首要目标是能够从Subversion/Git/Bazaar存储库中检出代码,并自动化其他任务。@battal-他不需要理由,他只想这么做。停止这种必须知道每个不相关的细节才能回答问题的想法。我不推荐最后一个选项,让密码在命令中可见。在服务器上运行
ps aux
的任何人都可以看到您的密码。谢谢Alexandre,但这不仅仅是登录需要密码。我还希望能够为我的框架的用户提供一个交互式会话,以便他们能够响应服务器可能发出的任何提示。公钥登录很好,只是不是为了这个目的。我只是以SSH登录为例。@Cameron密码提示很特殊,远程计算机不会显示它。一旦连接,您应该能够使用
$descriptorspec=array(0=>array(“pipe”,“r”),1=>array(“pipe”,“w”),2=>=>array(“pipe”,“w”))与shell交互。不过,最大的限制是,PHP资源(如管道)无法在会话中序列化(即在http请求之间保持),因此,例如基于web的终端模拟器是不可行的
<?php
include('Net/SSH2.php');

$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'password')) {
    exit('Login Failed');
}

echo $ssh->read('username@username:~$');
$ssh->write("ls -la\n");
echo $ssh->read('username@username:~$');
?>
import sys
import pty

args = " ".join(sys.argv[1:])
pty.spawn(['/usr/bin/ssh', args])