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

发布于 2024-09-30 17:16:37 字数 1448 浏览 11 评论 0原文

我正在尝试通过 Mac OS X 10.6 上的命令行使用 PHP 建立与远程服务器的交互式 SSH 连接。我目前正在使用 PHP 的 proc_open 函数来执行以下命令:

ssh -t -t -p 22 [email protected]

这几乎可以工作。 -t -t 选项应该强制使用伪终端,它们几乎做到了。我可以输入 SSH 密码并按 Enter 键。然而,按下 Enter 键后,终端似乎只是挂起。没有输出,什么也没有——就像 SSH 会话失败一样。我无法运行命令或任何东西,必须使用 Ctrl+C 杀死整个东西。我知道登录成功,因为我可以执行类似 ssh -t -t -p 22 [电子邮件受保护]“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 [email protected]', $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?这在 Mac OS X 上是不可能的吗?感谢您的帮助!

I'm trying to establish an interactive SSH connection to a remote server using PHP via the command line on Mac OS X 10.6. I'm currently using PHP's proc_open function to execute the following command:

ssh -t -t -p 22 [email protected]

This almost works. The -t -t options are supposed to force a pseudo terminal which they almost do. I am able to enter the SSH password and press enter. However, after pressing enter the terminal appears to simply hang. No output, no nothing - it's as if the SSH session has failed. I can't run commands or anything and have to kill the whole thing using Ctrl+C. I know the login is successful because I can execute a command like ssh -t -t -p 22 [email protected] "ls -la" and get the correct output.

I thought the problem must be related to the fact that I was using standard pipes in my proc_open call, so I replaced them with pty. I get the following error: "pty pseudo terminal not supported on this system..."

Does Mac OS X simply not support pty or pseudo terminals? (I'm pretty new at using all this shell terminology).

Here's the PHP code:

$descriptorspec = array(0 => array("pty"), 1 => array("pty"), 2 => array("pty"));  
$cwd = getcwd();  
$process = proc_open('ssh -t -t -p 22 [email protected]', $descriptorspec, $pipes, $cwd);  
if (is_resource($process))  
{  
    while (true)  
    {  
        echo(stream_get_contents($pipes[1]));  
        $status = proc_get_status($process);  
        if (! $status["running"])  
            break;  
    }  
} 

(Sorry - cannot for the life of me figure out SO's formatting instructions...)

What am I doing wrong? Why can't I use pty? Is this just impossible on Mac OS X? Thanks for your help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

岛歌少女 2024-10-07 17:16:38

您是否尝试过 PHP SSH2 扩展

Have you tried the PHP SSH2 extension?

你在看孤独的风景 2024-10-07 17:16:38

您是否尝试过 phpseclib,一个纯 PHP SSH 实现?:

<?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:~
);
?>

Have you tried 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->read('username@username:~
);
$ssh->write("ls -la\n");
echo $ssh->read('username@username:~
);
?>
若相惜即相离 2024-10-07 17:16:38

我用 ssh2 扩展在 php 上编写了一个 ssh 客户端,您可以在 github 页面上查看源代码 https://github.com/roke22/PHP-SSH2-Web-Client

请发送一些反馈。

I wrote a ssh client on php with ssh2 extension, you can take a look to the source code on the github page https://github.com/roke22/PHP-SSH2-Web-Client

Please send some feedback.

失去的东西太少 2024-10-07 17:16:37

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

密码提示应该是从 tty 使用的,我相信它是故意设置的,否则很难使用。此外,-t -t 参数仅在连接到远程主机后才会生效。而且我不相信 PHP 函数 proc_open() 可以在虚拟终端内运行命令。

要设置公钥身份验证:

# Generate keypair
ssh-keygen -t rsa

# Copy public key to server
scp ~/.ssh/id_rsa.pub example.com:.ssh/authorized_keys

# Now you shouldn't be prompted for a password when connecting to example.com
# from this host and user account.
ssh example.com

# Since the web server (and thus PHP) probably has its own user account...
# Copy the ~/.ssh/id_rsa file somewhere else
cp ~/.ssh/id_rsa /some_path/id_rsa

# Change ownership of the file to the web server account
chown www-data:www-data /some_path/id_rsa

# Fix the file permissions (ssh ignore the keyfile if it is world readable)
chown 600 /some_path/id_rsa

# Try connecting to the server through the web server account
su -c "ssh -i /some_path/id_rsa -o UserKnownHostsFile=/some_path/known_hosts example.com" www-data

# Add the host to the known hosts file when prompted

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

还有一个名为 sshpass 的程序,它从环境变量或命令参数中获取密码并将其传递给 ssh。

You should use public key authentication rather than trying to programmatically bypass interactive password authentication.

The password prompt is supposed to be used from a tty and I believe it was made intentionally difficult to use otherwise. Also the -t -t argument only takes effect once you are connected to the remote host. And I don't believe the PHP function proc_open() can run a command inside a virtual terminal.

To setup public key authentication:

# Generate keypair
ssh-keygen -t rsa

# Copy public key to server
scp ~/.ssh/id_rsa.pub example.com:.ssh/authorized_keys

# Now you shouldn't be prompted for a password when connecting to example.com
# from this host and user account.
ssh example.com

# Since the web server (and thus PHP) probably has its own user account...
# Copy the ~/.ssh/id_rsa file somewhere else
cp ~/.ssh/id_rsa /some_path/id_rsa

# Change ownership of the file to the web server account
chown www-data:www-data /some_path/id_rsa

# Fix the file permissions (ssh ignore the keyfile if it is world readable)
chown 600 /some_path/id_rsa

# Try connecting to the server through the web server account
su -c "ssh -i /some_path/id_rsa -o UserKnownHostsFile=/some_path/known_hosts example.com" www-data

# Add the host to the known hosts file when prompted

Alternately, you could use plink (part of PuTTY for Linux) instead of OpenSSH as it can take the password on the command line plink -pw password example.com. But doing so presents a security risk as anyone who runs ps aux on the server can see the password in the process list.

There is also a program called sshpass that takes the password from an environment variable or command argument and passes it to ssh.

孤檠 2024-10-07 17:16:37

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

It looks like the problem is best solved using PHP's passthru() function. After alot more (rather painful) research I was able to issue a command through this function and could interact with the remote server through the terminal as if I had run ssh and svn export by hand (they both require passwords, therefore were good tests). What I'm going to have to do is construct a (potentially very long) string of commands separated by && and attach them to the end of the ssh command: ssh -t -t -p 22 hostname command1 && command2 ... The output will be sent to my terminal in Mac OS X even though the commands are being executed on the remote server. Looks like this is the solution I was looking for the whole time - pretty simple really! Thanks to everyone who helped me with this. I gave Alexandre the "green checkmark" because he was the only one who kept responding and was quite helpful in deducing the final answer to the problem. Thanks Alexandre!

怪我入戏太深 2024-10-07 17:16:37

这是旧的,但对于任何 googlers 来说,这里是一个使用 proc_open 的实际解决方案:

Pty 描述符在 PHP 中可用,但必须在编译期间配置(请参阅这个 10 年前的错误报告 https://bugs.php.net/bug.php?id=33147)

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

import sys
import pty

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

来自 python 文档的 About pty.spawn:

生成一个进程,并将其控制终端与当前进程连接
进程的标准io.这通常用于阻碍程序
坚持从控制终端读取。

This is old, but for any googlers out there, here is an actual solution using proc_open:

Pty descriptors are available in PHP, but have to be configured during compilation (see this 10yr old bug report https://bugs.php.net/bug.php?id=33147)

But in python however, we don't have that problem. So instead of running the ssh command directly, run this python script:

import sys
import pty

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

About pty.spawn from python docs:

Spawn a process, and connect its controlling terminal with the current
process’s standard io. This is often used to baffle programs which
insist on reading from the controlling terminal.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文