使用Symfony Process通过PHP控制交互式过程 [英] Controlling an interactive process with PHP using Symfony Process

查看:117
本文介绍了使用Symfony Process通过PHP控制交互式过程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过添加新密钥来控制系统 ssh代理使用 ssh-add .为此,我使用了 Symfony Process 组件.

当我从网站上运行此代码时,它工作得很好,但是当我在shell/控制台中运行相同的代码时,ssh-add进程挂在Enter passphrase for <path to key>:

简化的代码看起来像这样

use Symfony\Component\Process\Process;

$keyPath = '<path to key>';
$keyPassword = '<password for unlocking the key>';
$socketPath = '<path to ssh-agent socket>';

$sshAdd = new Process(
    "ssh-add {$keyPath}",
    null,
    [
        'SSH_AUTH_SOCK' => $socketPath
    ],
    $keyPassword
);
$sshAdd->run();

如您在上面的代码中看到的,我调用了ssh-add,在环境中设置了SSH_AUTH_SOCK,以便ssh-add可以与代理对话,然后在输入中发送密码.如前所述,当我在Web上下文中运行它时,它可以工作,但是挂在Shell/控制台上下文中.

在控制台中运行时,我做了strace的操作,相关部分看起来像这样

open("<path to key>", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
write(4, "<key password>", <length of password>)      = 20
close(4)                                              = 0
wait4(9650, 0x7fff00ab3554, WNOHANG|WSTOPPED, NULL)   = 0
select(8, [5 7], [], [], {0, 0})                      = 0 (Timeout)
wait4(9650, 0x7fff00ab3554, WNOHANG|WSTOPPED, NULL)   = 0
select(8, [5 7], [], [], {0, 0})                      = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000}Enter passphrase for <path to key>:) = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
...

您可以看到,写入似乎被忽略了,并且ssh-add程序开始阻止等待输入.

解决方案

阅读ssh-add的源代码并阅读

I am trying to control the systems ssh-agent by adding new keys to it using ssh-add. For this I'm using the Symfony Process component.

When I run this code from a web site it works perfectly fine but when I run the same code in a shell/console the ssh-add process hangs on Enter passphrase for <path to key>:

A simplified version of the code looks something like this

use Symfony\Component\Process\Process;

$keyPath = '<path to key>';
$keyPassword = '<password for unlocking the key>';
$socketPath = '<path to ssh-agent socket>';

$sshAdd = new Process(
    "ssh-add {$keyPath}",
    null,
    [
        'SSH_AUTH_SOCK' => $socketPath
    ],
    $keyPassword
);
$sshAdd->run();

As you can see in the code above I make a call to ssh-add, sets the SSH_AUTH_SOCK in the environment so ssh-add can talk to the agent and then sends the password in the input. As I said previously, when I run this in a web context it works but it hangs in a shell/console context.

I did an strace of when running in the console and the relevant parts looks like this

open("<path to key>", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
write(4, "<key password>", <length of password>)      = 20
close(4)                                              = 0
wait4(9650, 0x7fff00ab3554, WNOHANG|WSTOPPED, NULL)   = 0
select(8, [5 7], [], [], {0, 0})                      = 0 (Timeout)
wait4(9650, 0x7fff00ab3554, WNOHANG|WSTOPPED, NULL)   = 0
select(8, [5 7], [], [], {0, 0})                      = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000}Enter passphrase for <path to key>:) = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
...

As you can see the write seems to be ignored and the ssh-add program starts to block waiting for input.

解决方案

Finally found a solution to this problem after reading the source for ssh-add and by reading this very old article from Wez Furlong where he talks about adding PTY support to PHP.

To quote the article:

What this does is similar to creating a pipe to the process, but instead creates master (for your script) and slave (for the process you're running) pty handles using the /dev/ptmx interface of your OS. This allows you to send to, and capture data from, applications that open /dev/tty explicitly--and this is generally done when interactively prompting for a password.

Turns out Symfony Process also supports PTY so the original code only needed a couple of changes. First I need to specify I want to use PTY instead of pipes by calling setPty(true). Then I need to simulate that the user has pressed ENTER after inputting the password simply by appending a line feed to the input.

The final code would look something like this (with comments on the changed lines)

use Symfony\Component\Process\Process;

$keyPath = '<path to key>';
$keyPassword = '<password for unlocking the key>';
$socketPath = '<path to ssh-agent socket>';

$sshAdd = new Process(
    "ssh-add {$keyPath}",
    null,
    [
        'SSH_AUTH_SOCK' => $socketPath
    ],
    $keyPassword . "\n"   // Append a line feed to simulate pressing ENTER
);
$sshAdd->setPty(true);   // Use PTY instead of the default pipes
$sshAdd->run();

这篇关于使用Symfony Process通过PHP控制交互式过程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆